aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2011-06-19 20:11:40 -0700
committerPaul Eggert2011-06-19 20:11:40 -0700
commit882f0d8119c9135b06ce9b291a139e4e9c6eeff8 (patch)
treed94f839b5aba81b3a9cf78554b054ef5149b63d8 /src
parent93f4cf88953806d319e6ab231b4d1332a227d645 (diff)
downloademacs-882f0d8119c9135b06ce9b291a139e4e9c6eeff8.tar.gz
emacs-882f0d8119c9135b06ce9b291a139e4e9c6eeff8.zip
* filelock.c: Fix some buffer overrun and integer overflow issues.
(get_boot_time): Don't assume that gzip command string fits in 100 bytes. Reformulate so as not to need the command string. Invoke gzip -cd rather than gunzip, as it's more portable. (lock_info_type, lock_file_1, lock_file): Don't assume pid_t and time_t fit in unsigned long. (LOCK_PID_MAX): Remove; we now use more-reliable bounds. (current_lock_owner): Prefer signed type for sizes. Use memcpy, not strncpy, where memcpy is what is really wanted. Don't assume (via atoi) that time_t and pid_t fit in int. Check for time_t and/or pid_t out of range, e.g., via a network share. Don't alloca where an auto var works fine.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog15
-rw-r--r--src/filelock.c89
2 files changed, 62 insertions, 42 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 3687da81fbb..fd17f85f1e1 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,18 @@
12011-06-20 Paul Eggert <eggert@cs.ucla.edu>
2
3 * filelock.c: Fix some buffer overrun and integer overflow issues.
4 (get_boot_time): Don't assume that gzip command string fits in 100 bytes.
5 Reformulate so as not to need the command string.
6 Invoke gzip -cd rather than gunzip, as it's more portable.
7 (lock_info_type, lock_file_1, lock_file):
8 Don't assume pid_t and time_t fit in unsigned long.
9 (LOCK_PID_MAX): Remove; we now use more-reliable bounds.
10 (current_lock_owner): Prefer signed type for sizes.
11 Use memcpy, not strncpy, where memcpy is what is really wanted.
12 Don't assume (via atoi) that time_t and pid_t fit in int.
13 Check for time_t and/or pid_t out of range, e.g., via a network share.
14 Don't alloca where an auto var works fine.
15
12011-06-19 Paul Eggert <eggert@cs.ucla.edu> 162011-06-19 Paul Eggert <eggert@cs.ucla.edu>
2 17
3 * fileio.c: Fix some integer overflow issues. 18 * fileio.c: Fix some integer overflow issues.
diff --git a/src/filelock.c b/src/filelock.c
index 13b27c72f19..18483b6f3f3 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -168,7 +168,7 @@ get_boot_time (void)
168 /* If we did not find a boot time in wtmp, look at wtmp, and so on. */ 168 /* If we did not find a boot time in wtmp, look at wtmp, and so on. */
169 for (counter = 0; counter < 20 && ! boot_time; counter++) 169 for (counter = 0; counter < 20 && ! boot_time; counter++)
170 { 170 {
171 char cmd_string[100]; 171 char cmd_string[sizeof WTMP_FILE ".19.gz"];
172 Lisp_Object tempname, filename; 172 Lisp_Object tempname, filename;
173 int delete_flag = 0; 173 int delete_flag = 0;
174 174
@@ -191,19 +191,16 @@ get_boot_time (void)
191 character long prefix, and call make_temp_file with 191 character long prefix, and call make_temp_file with
192 second arg non-zero, so that it will add not more 192 second arg non-zero, so that it will add not more
193 than 6 characters to the prefix. */ 193 than 6 characters to the prefix. */
194 tempname = Fexpand_file_name (build_string ("wt"), 194 filename = Fexpand_file_name (build_string ("wt"),
195 Vtemporary_file_directory); 195 Vtemporary_file_directory);
196 tempname = make_temp_name (tempname, 1); 196 filename = make_temp_name (filename, 1);
197 args[0] = Vshell_file_name; 197 args[0] = build_string ("gzip");
198 args[1] = Qnil; 198 args[1] = Qnil;
199 args[2] = Qnil; 199 args[2] = list2 (QCfile, filename);
200 args[3] = Qnil; 200 args[3] = Qnil;
201 args[4] = build_string ("-c"); 201 args[4] = build_string ("-cd");
202 sprintf (cmd_string, "gunzip < %s.%d.gz > %s", 202 args[5] = tempname;
203 WTMP_FILE, counter, SDATA (tempname));
204 args[5] = build_string (cmd_string);
205 Fcall_process (6, args); 203 Fcall_process (6, args);
206 filename = tempname;
207 delete_flag = 1; 204 delete_flag = 1;
208 } 205 }
209 } 206 }
@@ -284,14 +281,10 @@ typedef struct
284{ 281{
285 char *user; 282 char *user;
286 char *host; 283 char *host;
287 unsigned long pid; 284 pid_t pid;
288 time_t boot_time; 285 time_t boot_time;
289} lock_info_type; 286} lock_info_type;
290 287
291/* When we read the info back, we might need this much more,
292 enough for decimal representation plus null. */
293#define LOCK_PID_MAX (4 * sizeof (unsigned long))
294
295/* Free the two dynamically-allocated pieces in PTR. */ 288/* Free the two dynamically-allocated pieces in PTR. */
296#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0) 289#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
297 290
@@ -344,7 +337,7 @@ static int
344lock_file_1 (char *lfname, int force) 337lock_file_1 (char *lfname, int force)
345{ 338{
346 register int err; 339 register int err;
347 time_t boot; 340 intmax_t boot, pid;
348 const char *user_name; 341 const char *user_name;
349 const char *host_name; 342 const char *host_name;
350 char *lock_info_str; 343 char *lock_info_str;
@@ -361,14 +354,16 @@ lock_file_1 (char *lfname, int force)
361 else 354 else
362 host_name = ""; 355 host_name = "";
363 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name) 356 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
364 + LOCK_PID_MAX + 30); 357 + 2 * INT_STRLEN_BOUND (intmax_t)
358 + sizeof "@.:");
359 pid = getpid ();
365 360
366 if (boot) 361 if (boot)
367 sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name, 362 sprintf (lock_info_str, "%s@%s.%"PRIdMAX":%"PRIdMAX,
368 (unsigned long) getpid (), (unsigned long) boot); 363 user_name, host_name, pid, boot);
369 else 364 else
370 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name, 365 sprintf (lock_info_str, "%s@%s.%"PRIdMAX,
371 (unsigned long) getpid ()); 366 user_name, host_name, pid);
372 367
373 err = symlink (lock_info_str, lfname); 368 err = symlink (lock_info_str, lfname);
374 if (errno == EEXIST && force) 369 if (errno == EEXIST && force)
@@ -397,8 +392,9 @@ static int
397current_lock_owner (lock_info_type *owner, char *lfname) 392current_lock_owner (lock_info_type *owner, char *lfname)
398{ 393{
399 int ret; 394 int ret;
400 size_t len; 395 ptrdiff_t len;
401 int local_owner = 0; 396 lock_info_type local_owner;
397 intmax_t n;
402 char *at, *dot, *colon; 398 char *at, *dot, *colon;
403 char readlink_buf[READLINK_BUFSIZE]; 399 char readlink_buf[READLINK_BUFSIZE];
404 char *lfinfo = emacs_readlink (lfname, readlink_buf); 400 char *lfinfo = emacs_readlink (lfname, readlink_buf);
@@ -408,12 +404,9 @@ current_lock_owner (lock_info_type *owner, char *lfname)
408 return errno == ENOENT ? 0 : -1; 404 return errno == ENOENT ? 0 : -1;
409 405
410 /* Even if the caller doesn't want the owner info, we still have to 406 /* Even if the caller doesn't want the owner info, we still have to
411 read it to determine return value, so allocate it. */ 407 read it to determine return value. */
412 if (!owner) 408 if (!owner)
413 { 409 owner = &local_owner;
414 owner = (lock_info_type *) alloca (sizeof (lock_info_type));
415 local_owner = 1;
416 }
417 410
418 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ 411 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
419 /* The USER is everything before the last @. */ 412 /* The USER is everything before the last @. */
@@ -427,24 +420,34 @@ current_lock_owner (lock_info_type *owner, char *lfname)
427 } 420 }
428 len = at - lfinfo; 421 len = at - lfinfo;
429 owner->user = (char *) xmalloc (len + 1); 422 owner->user = (char *) xmalloc (len + 1);
430 strncpy (owner->user, lfinfo, len); 423 memcpy (owner->user, lfinfo, len);
431 owner->user[len] = 0; 424 owner->user[len] = 0;
432 425
433 /* The PID is everything from the last `.' to the `:'. */ 426 /* The PID is everything from the last `.' to the `:'. */
434 owner->pid = atoi (dot + 1); 427 errno = 0;
435 colon = dot; 428 n = strtoimax (dot + 1, NULL, 10);
436 while (*colon && *colon != ':') 429 owner->pid =
437 colon++; 430 ((0 <= n && n <= TYPE_MAXIMUM (pid_t)
431 && (TYPE_MAXIMUM (pid_t) < INTMAX_MAX || errno != ERANGE))
432 ? n : 0);
433
434 colon = strchr (dot + 1, ':');
438 /* After the `:', if there is one, comes the boot time. */ 435 /* After the `:', if there is one, comes the boot time. */
439 if (*colon == ':') 436 n = 0;
440 owner->boot_time = atoi (colon + 1); 437 if (colon)
441 else 438 {
442 owner->boot_time = 0; 439 errno = 0;
440 n = strtoimax (colon + 1, NULL, 10);
441 }
442 owner->boot_time =
443 ((0 <= n && n <= TYPE_MAXIMUM (time_t)
444 && (TYPE_MAXIMUM (time_t) < INTMAX_MAX || errno != ERANGE))
445 ? n : 0);
443 446
444 /* The host is everything in between. */ 447 /* The host is everything in between. */
445 len = dot - at - 1; 448 len = dot - at - 1;
446 owner->host = (char *) xmalloc (len + 1); 449 owner->host = (char *) xmalloc (len + 1);
447 strncpy (owner->host, at + 1, len); 450 memcpy (owner->host, at + 1, len);
448 owner->host[len] = 0; 451 owner->host[len] = 0;
449 452
450 /* We're done looking at the link info. */ 453 /* We're done looking at the link info. */
@@ -476,7 +479,7 @@ current_lock_owner (lock_info_type *owner, char *lfname)
476 } 479 }
477 480
478 /* Avoid garbage. */ 481 /* Avoid garbage. */
479 if (local_owner || ret <= 0) 482 if (owner == &local_owner || ret <= 0)
480 { 483 {
481 FREE_LOCK_INFO (*owner); 484 FREE_LOCK_INFO (*owner);
482 } 485 }
@@ -539,6 +542,7 @@ lock_file (Lisp_Object fn)
539 register Lisp_Object attack, orig_fn, encoded_fn; 542 register Lisp_Object attack, orig_fn, encoded_fn;
540 register char *lfname, *locker; 543 register char *lfname, *locker;
541 lock_info_type lock_info; 544 lock_info_type lock_info;
545 intmax_t pid;
542 struct gcpro gcpro1; 546 struct gcpro gcpro1;
543 547
544 /* Don't do locking while dumping Emacs. 548 /* Don't do locking while dumping Emacs.
@@ -577,9 +581,10 @@ lock_file (Lisp_Object fn)
577 581
578 /* Else consider breaking the lock */ 582 /* Else consider breaking the lock */
579 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host) 583 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
580 + LOCK_PID_MAX + 9); 584 + INT_STRLEN_BOUND (intmax_t) + sizeof "@ (pid )");
581 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host, 585 pid = lock_info.pid;
582 lock_info.pid); 586 sprintf (locker, "%s@%s (pid %"PRIdMAX")",
587 lock_info.user, lock_info.host, pid);
583 FREE_LOCK_INFO (lock_info); 588 FREE_LOCK_INFO (lock_info);
584 589
585 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker)); 590 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));