Source: psmisc Version: 22.13-1 Severity: important Tags: patch Hi Craig,
Two quick fixes in the ongoing fight against hurd. killall uses a buffer of size PATH_MAX (why not SYMLINK_MAX?) to hold the link target when falling back to comparing /proc/<pid>/exe to the <path> passed on the command line. On platforms with no PATH_MAX, it therefore fails to build from source. Patch 1 switches to a buffer of size strlen("<path>") + 1, which should be large enough to fit a symlink target that matches and to determine whether the actual target is longer. The buffer was missing a null-terminator and tested using strcmp, so patch 1 switches to memcmp while at it. Patch 2 teaches killall to look at /proc/$$/stat instead of /proc/self/stat to see whether /proc is mounted at all. Hurd supports the former but not the latter (luckily killall doesn't seem to need /proc/self aside from that sanity check). So now you can use "killall foo" to kill all instances of "foo" even on hurd. Thoughts?
>From 0adb16446bb02c802a68c9d51f69fe61f92a646a Mon Sep 17 00:00:00 2001 From: Jonathan Nieder <jrnie...@gmail.com> Date: Tue, 19 Apr 2011 23:19:35 -0500 Subject: [PATCH 1/2] killall: fix textual path comparison fallback Ever since psmisc 22.4 (2007-04-08), "killall <path>" compares the target of the /proc/<pid>/exe link to <path> when comparison of inode numbers fails. But the code to do this has two problems: - readlink does not NUL-terminate, but we use strcmp to compare strings. Probably this hasn't been a problem so far because (1) the on-stack buffer happened to have zeroes in the right places or (2) some implementations of readlink might happen to NUL-terminate their result when convenient anyway. - it relies on PATH_MAX to determine the size of the buffer, so the code fails to build from source on platforms (like the Hurd) that have no global PATH_MAX. Fix both by using a buffer of size strlen("<path>") + 1 and comparing the link target to <path> with memcmp after checking that it fit in the buffer. For consistency with the surrounding code, the pid is considered not to match if malloc or readlink fails. Signed-off-by: Jonathan Nieder <jrnie...@gmail.com> --- src/killall.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/killall.c b/src/killall.c index 8b590c2..93de30d 100644 --- a/src/killall.c +++ b/src/killall.c @@ -511,11 +511,14 @@ kill_all (int signal, int names, char **namelist, struct passwd *pwent) /* maybe the binary has been modified and std[j].st_ino * is not reliable anymore. We need to compare paths. */ - char linkbuf[PATH_MAX]; + size_t len = strlen(namelist[j]); + char *linkbuf = malloc(len + 1); - if (readlink(path, linkbuf, sizeof(linkbuf)) <= 0 || - strcmp(namelist[j], linkbuf)) + if (!linkbuf || + readlink(path, linkbuf, len + 1) != len || + memcmp(namelist[j], linkbuf, len)) ok = 0; + free(linkbuf); } free(path); -- 1.7.5.rc2
>From efc08c926a8dbf5af4b956613dc862280e1b33df Mon Sep 17 00:00:00 2001 From: Jonathan Nieder <jrnie...@gmail.com> Date: Wed, 20 Apr 2011 00:12:00 -0500 Subject: [PATCH 2/2] killall: tolerate platforms without /proc/self The Hurd has most of the expected /proc/<pid> hierarchy but no /proc/self. Without this change, running "sleep 10 & killall sleep" on that platform produces the confusing message: /proc is empty (not mounted ?) Afterwards, we will get $ sleep 10 & killall sleep [1] 9682 [1]+ Terminated sleep 10 as expected. Signed-off-by: Jonathan Nieder <jrnie...@gmail.com> --- src/killall.c | 16 +++++++++++++--- 1 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/killall.c b/src/killall.c index 93de30d..ac3a279 100644 --- a/src/killall.c +++ b/src/killall.c @@ -686,6 +686,17 @@ void print_version() "For more information about these matters, see the files named COPYING.\n")); } +static int +have_proc_self_stat (void) +{ + char filename[128]; + struct stat isproc; + pid_t pid = getpid(); + + snprintf(filename, sizeof(filename), PROC_BASE"/%d/stat", (int) pid); + return stat(filename, &isproc) == 0; +} + int main (int argc, char **argv) { @@ -694,7 +705,6 @@ main (int argc, char **argv) int optc; int myoptind; struct passwd *pwent = NULL; - struct stat isproc; char yt[16]; char ot[16]; @@ -860,8 +870,8 @@ main (int argc, char **argv) fprintf (stderr, _("Maximum number of names is %d\n"), MAX_NAMES); exit (1); } - if (stat("/proc/self/stat", &isproc)==-1) { - fprintf (stderr, _("%s is empty (not mounted ?)\n"), PROC_BASE); + if (!have_proc_self_stat()) { + fprintf (stderr, _("%s lacks process entries (not mounted ?)\n"), PROC_BASE); exit (1); } argv = argv + myoptind; -- 1.7.5.rc2