Bug 15496

Summary: killall(1) limited to 16 character process names by procfs(5)
Product: Base System Reporter: m.seaman <m.seaman>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff none

Description m.seaman 1999-12-15 15:50:00 UTC
	killall(1) reads procfs /proc/${pid}/status entries to find
the process names the user wants to kill.  However, only the first 16
(MAXCOMLEN from /usr/include/sys/param.h) characters of the process
name are available.  Trying naively to killall(1) a process with a
longer name is guarranteed to fail: instead the supplied name should
be truncated to the first 16 characters.

	I'm not convinced that modifying procfs() to fix this somewhat
obscure case is really going to be worthwhile.  This should certainly
be documented though.

How-To-Repeat: 
b0:/tmp:% cat foo.c
#include <unistd.h>

int
main (int argc, char *argv[])
{
        sleep(600);
}
b0:/tmp:% cc -o 1234567890123 foo.c 
b0:/tmp:% cp 1234567890123{,4}
b0:/tmp:% cp 1234567890123{,45}
b0:/tmp:% cp 1234567890123{,456}
b0:/tmp:% cp 1234567890123{,4567}
b0:/tmp:% ./12345678901234 & 
[4] 63828
b0:/tmp:% ./12345678901235 &
[5] 63829
b0:/tmp:% ./123456789012345 &
[6] 63830
b0:/tmp:% ./1234567890123456 &
[7] 63831
b0:/tmp:% ./12345678901234567 &
[8] 63832
b0:/tmp:% head /proc/{63826,63828,63830,63831,63832}/status
==> /proc/63826/status <==
1234567890123 63826 63513 63826 63513 5,2 ctty 945270683,3518 0,1030 0,6184 nanslp 1000 1000 1000,1000,1000,0,999,1018,994,993,997

==> /proc/63828/status <==
12345678901234 63828 63513 63828 63513 5,2 ctty 945270704,936540 0,909 0,6369 nanslp 1000 1000 1000,1000,1000,0,999,1018,994,993,997

==> /proc/63830/status <==
123456789012345 63830 63513 63830 63513 5,2 ctty 945270715,716412 0,3262 0,4349 nanslp 1000 1000 1000,1000,1000,0,999,1018,994,993,997

==> /proc/63831/status <==
1234567890123456 63831 63513 63831 63513 5,2 ctty 945270719,857664 0,1879 0,5639 nanslp 1000 1000 1000,1000,1000,0,999,1018,994,993,997

==> /proc/63832/status <==
1234567890123456 63832 63513 63832 63513 5,2 ctty 945270723,443053 0,2114 0,5287 nanslp 1000 1000 1000,1000,1000,0,999,1018,994,993,997
b0:/tmp:% killall 12345678901234567
No processes matching ``12345678901234567''
Comment 1 Sheldon Hearn 1999-12-17 10:38:53 UTC
On Wed, 15 Dec 1999 15:48:18 GMT, m.seaman@inpharmatica.co.uk wrote:

> 	killall(1) reads procfs /proc/${pid}/status entries to find
> the process names the user wants to kill.

Can we get the process names anywhere else?

Ciao,
Sheldon.
Comment 2 m.seaman 1999-12-17 15:29:31 UTC
Sheldon Hearn wrote:
> 
> On Wed, 15 Dec 1999 15:48:18 GMT, m.seaman@inpharmatica.co.uk wrote:
> 
> >       killall(1) reads procfs /proc/${pid}/status entries to find
> > the process names the user wants to kill.
> 
> Can we get the process names anywhere else?

Hmmm... The only other prospect in /proc is the 'cmdline' entry, but that has
the same 16 character limitation as the status entry.

st-pancras:/tmp:% ./12345678901234567 & 
[1] 79007
st-pancras:/tmp:% cd /proc/79007
st-pancras:/proc/79007:% cat cmdline 
1234567890123456st-pancras:/proc/79007:% 

Failing that, we could parse the output of /bin/ps -ax --- easily doable from
perl, but dependent on processes not mangling argv[0] in unforeseen ways (ps
-axc has the same 16 character limitation as above).

Otherwise, we'd be looking at reading kvm the way ps(1) does, which is
not much fun from perl: it would probably be necessary to implement a
FreeBSD::KVM module using the perl '.xs' code thingy to generate an interface
to the kvm functions.  Plus we would have to use suidperl to run the script
setgid to kmem, which doesn't strike me as particularly desirable.

Hmmm... here's a patch to killall(1) to use ps(1) output as well as reading
/proc:  ps(1) output is used if the given program-name-to-kill is longer than
16 characters, or a match could not otherwise be made, to distinguish between
similarly named processes around 16 characters long. eg:

st-pancras:~:% /tmp/1234567890123456 & 
[1] 79288
st-pancras:~:% /tmp/12345678901234567 &
[2] 79289
st-pancras:~:% ./killall.pl -v 12345678901234567
kill -TERM 79289
[2]  - Terminated                    /tmp/12345678901234567
st-pancras:~:% ./killall.pl -v 1234567890123456
kill -TERM 79288
[1]  + Terminated                    /tmp/1234567890123456


 diff -u killall.pl.orig killall.pl 
--- killall.pl.orig  Tue Aug 31 10:08:27 1999
+++ killall.pl     Fri Dec 17 15:19:39 1999
@@ -30,11 +30,13 @@
 
 
 $ENV{'PATH'} = '/bin:/usr/bin'; # security
+$pscmd = '/bin/ps -ax';                # list all processes
 $procfs = '/proc';
 $signal = 'SIGTERM';           # default signal for kill
 $debug = 0;
 $match = 0;                    # 0 match exactly program name
 $show = 0;                     # do nothings
+%procs = ();                   # Lookup processes by PID
 
 # see /sys/miscfs/procfs/procfs_status.c
 $PROC_NAME =  0;
@@ -68,6 +70,23 @@
 undef %pidu;
 undef %thiskill;
 
+open(PS, "$pscmd|") || die "$pscmd $!\n";
+while (<PS>) {
+    my ($pid, $proc);
+    chomp;
+
+    # Processes can alter their argv[0], which will be reflected in
+    # ps(1) output, so this is by no means reliable.  Typically login
+    # shells will have `-' pre-pended.  System processes like swapper
+    # are usually in (brackets) and then there's sendmail and nfsd that
+    # use argv[0] for status messages.
+
+    if (($pid, $proc) = m/^\s*(\d+)\s+\S+\s+\S+\s+\S+\s+(\S+)/) {
+         ($procs{$pid} = $proc) =~ s@.*/@@;    # Strip any leading path
+    }
+}
+close(PS);
+
 foreach (sort{$a <=> $b} grep(/^[0-9]/, readdir(PROCFS))) {
     $status = "$procfs/$_/status";
     $pid = $_;
@@ -85,8 +104,12 @@
            ($programMatch = $program) =~ s/(\W)/\\$1/g if $match;
 
             # match program name
-           if ($proc[$PROC_NAME] eq $program ||
-               ($match && $proc[$PROC_NAME] =~ /$programMatch/i)) {
+           if ( (length $program <= 16 && 
+                 ($proc[$PROC_NAME] eq $program ||
+                  ($match && $proc[$PROC_NAME] =~ /$programMatch/i))) ||
+                (defined $procs{$pid} && 
+                 ($procs{$pid} eq $program ||
+                  ($match && $procs{$pid} =~ /$programMatch/i)))) {
 
                # id test
                if ($proc[$PROC_EUID] eq $id || # effective uid


-- 
           Certe, Toto, sentio nos in Kansate non iam adesse.

   Dr. Matthew Seaman, Inpharmatica Ltd, 60 Charlotte St, London, W1P 2AX
            Tel: +44 171 631 4644 x229  Fax: +44 171 631 4844
Comment 3 m.seaman 2000-09-26 14:22:11 UTC
Since killall(1) has recently transmogrified into a C program, I guess this PR
might be closable.  However, the same bug still seems to be present:

st-pancras:/tmp:# uname -a
FreeBSD st-pancras.inpharmatica.co.uk 4.1.1-STABLE FreeBSD 4.1.1-STABLE #0:
Tue Sep 26 12:32:33 BST 2000    
root@st-pancras.inpharmatica.co.uk:/export/i386/obj/export/src/sys/ST-PANCRAS 
i386
st-pancras:/tmp:# file /usr/bin/killall
/usr/bin/killall: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD),
dynamically linked, stripped
st-pancras:/tmp:# ./123456789012345 & 
[1] 249
st-pancras:/tmp:# ./1234567890123456 &
[2] 250
st-pancras:/tmp:# ./12345678901234567 &
[3] 251
st-pancras:/tmp:# head /proc/{249,250,251}/status 
==> /proc/249/status <==
123456789012345 249 227 249 227 5,0 ctty 969973928,166376 0,0 0,6293 nanslp 0
0 0,0,0,2,3,4,5,20,31,994,998 -

==> /proc/250/status <==
1234567890123456 250 227 250 227 5,0 ctty 969973930,750074 0,0 0,6484 nanslp 0
0 0,0,0,2,3,4,5,20,31,994,998 -

==> /proc/251/status <==
1234567890123456 251 227 251 227 5,0 ctty 969973934,657696 0,0 0,6582 nanslp 0
0 0,0,0,2,3,4,5,20,31,994,998 -
st-pancras:/tmp:# killall 12345678901234567 
No matching processes were found
st-pancras:/tmp:# killall 1234567890123456
[3]  - Terminated                    ./12345678901234567
[2]  - Terminated                    ./1234567890123456

	Cheers,

	Matthew

-- 
           Certe, Toto, sentio nos in Kansate non iam adesse.

   Dr. Matthew Seaman, Inpharmatica Ltd, 60 Charlotte St, London, W1T 2NU
            Tel: +44 20 7631 4644 x229  Fax: +44 20 7631 4844
Comment 4 dd freebsd_committer freebsd_triage 2001-06-18 23:30:44 UTC
State Changed
From-To: open->closed

killall doesn't use procfs anymore.