* [RFC][PATCH] killall context regex and userid matching
@ 2005-09-01 18:56 ltcgcw
2005-09-01 21:10 ` [redhat-lspp] " Daniel J Walsh
2005-09-02 15:03 ` Stephen Smalley
0 siblings, 2 replies; 3+ messages in thread
From: ltcgcw @ 2005-09-01 18:56 UTC (permalink / raw)
To: SELinux; +Cc: redhat-lspp
[-- Attachment #1: Type: text/plain, Size: 652 bytes --]
Please find a patch to psmisc attached. It adds these features to killall:
- regular expression SELinux context matching
- userid matching
- process names now optional when matching by either context or userid
- most fprintf() strings now gettext-ized
- help text no longer split up by #ifdef; missing newline added
- manpage updates
The patch applies to the psmisc CVS tree, current as of today. I will
submit it to the psmisc maintainer once I incorporate comments received on
this list. It might be useful to add something similar to skill and snice.
--
George Wilson <ltcgcw@us.ibm.com>
IBM Linux Technology Center
[-- Attachment #2: psmisc-16.patch --]
[-- Type: text/plain, Size: 16215 bytes --]
diff -Naurp psmisc.orig/doc/killall.1 psmisc.comp/doc/killall.1
--- psmisc.orig/doc/killall.1 2005-03-20 18:02:44.000000000 -0600
+++ psmisc.comp/doc/killall.1 2005-08-28 16:17:58.000000000 -0500
@@ -4,13 +4,16 @@ killall \- kill processes by name
.SH SYNOPSIS
.ad l
.B killall
-.RB [ \-Z , \-\-context ]
+.RB [ \-Z , \-\-context
+.IR regex ]
.RB [ \-e , \-\-exact ]
.RB [ \-g , \-\-process\-group ]
.RB [ \-i , \-\-interactive ]
.RB [ \-q , \-\-quiet ]
.RB [ \-s , \-\-signal
.IR signal ]
+.RB [ \-u , \-\-user
+.IR user ]
.RB [ \-v , \-\-verbose ]
.RB [ \-w , \-\-wait ]
.RB [ \-I , \-\-ignore-case ]
@@ -36,7 +39,9 @@ If the command name contains a slash (\f
particular file will be selected for killing, independent of their name.
.PP
\fBkillall\fP returns a zero return code if at least one process has been
-killed for each listed command. \fBkillall\fP returns non-zero otherwise.
+killed for each listed command, or no commands were listed and at least
+one process matched the -u and -Z search criteria. \fBkillall\fP returns
+non-zero otherwise.
.PP
A \fBkillall\fP process never kills itself (but may kill other \fBkillall\fP
processes).
@@ -60,6 +65,8 @@ Interactively ask for confirmation befor
List all known signal names.
.IP "\fB\-q\fP, \fB\-\-quiet\fP"
Do not complain if no processes were killed.
+.IP "\fB\-u\fP, \fB\-\-user\fP"
+Kill only processes the specified user owns. Command names are optional.
.IP "\fB\-v\fP, \fB\-\-verbose\fP"
Report if the signal was successfully sent.
.IP "\fB\-V\fP, \fB\-\-version\fP"
@@ -69,9 +76,9 @@ Wait for all killed processes to die. \f
any of the killed processes still exist and only returns if none are left.
Note that \fBkillall\fP may wait forever if the signal was ignored, had no
effect, or if the process stays in zombie state.
-.IP \fB\-Z\fP
-(SELinux Only) Specify security context: kill only processes with given security context.
-Must precede other arguments on the command line.
+.IP "\fB\-Z\fP, \fB\-\-context\fP"
+(SELinux Only) Kill only processes having a security context that matches the
+given extended regular expression. Command names are optional.
.SH FILES
.nf
/proc location of the proc file system
diff -Naurp psmisc.orig/src/killall.c psmisc.comp/src/killall.c
--- psmisc.orig/src/killall.c 2005-03-23 16:38:00.000000000 -0600
+++ psmisc.comp/src/killall.c 2005-08-29 07:33:39.000000000 -0500
@@ -39,15 +39,16 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
-
-#ifdef WITH_SELINUX
-#include <selinux/selinux.h>
-#endif /*WITH_SELINUX*/
+#include <pwd.h>
#include "i18n.h"
#include "comm.h"
#include "signals.h"
+#ifdef WITH_SELINUX
+#include <regex.h>
+#include <selinux/selinux.h>
+#endif /*WITH_SELINUX*/
#define PROC_BASE "/proc"
#define MAX_NAMES (int)(sizeof(unsigned long)*8)
@@ -55,7 +56,7 @@
static int verbose = 0, exact = 0, interactive = 0,
quiet = 0, wait_until_dead = 0, process_group = 0,
- ignore_case = 0, pidof;
+ ignore_case = 0, byuser = 0, pidof;
static int
ask (char *name, pid_t pid)
@@ -90,10 +91,10 @@ ask (char *name, pid_t pid)
#ifdef WITH_SELINUX
static int
-kill_all(int signal, int names, char **namelist, security_context_t scontext )
+kill_all(int signal, int names, char **namelist, uid_t *uid, regex_t *context_regex)
#else /*WITH_SELINUX*/
static int
-kill_all (int signal, int names, char **namelist)
+kill_all (int signal, int names, char **namelist, uid_t *uid)
#endif /*WITH_SELINUX*/
{
DIR *dir;
@@ -109,28 +110,41 @@ kill_all (int signal, int names, char **
int empty, i, j, okay, length, got_long, error;
int pids, max_pids, pids_killed;
unsigned long found;
+ uid_t ps_uid = 0;
+ const int ps_buffer_size = 80;
+ char ps_buffer[ps_buffer_size];
+ int rc = 0;
#ifdef WITH_SELINUX
- security_context_t lcontext=NULL;
-
- if ( names == 0 || ! namelist ) exit( 1 ); /* do the obvious thing...*/
+ int nameless = ((names == 0) && ((uid != NULL) || (context_regex != NULL)));
+ security_context_t ps_context = NULL;
+#else
+ int nameless = (names == 0) && (uid != NULL);
#endif /*WITH_SELINUX*/
- if (!(name_len = malloc (sizeof (int) * names)))
+ if (!nameless)
{
- perror ("malloc");
- exit (1);
+ if (!(name_len = malloc (sizeof (int) * names)))
+ {
+ perror ("malloc");
+ exit (1);
+ }
+ for (i = 0; i < names; i++)
+ {
+ if (!strchr (namelist[i], '/'))
+ {
+ sts[i].st_dev = 0;
+ name_len[i] = strlen (namelist[i]);
+ }
+ else if (stat (namelist[i], &sts[i]) < 0)
+ {
+ perror (namelist[i]);
+ exit (1);
+ }
+ }
}
- for (i = 0; i < names; i++) {
- if (!strchr (namelist[i], '/'))
- {
- sts[i].st_dev = 0;
- name_len[i] = strlen (namelist[i]);
- }
- else if (stat (namelist[i], &sts[i]) < 0)
- {
- perror (namelist[i]);
- exit (1);
- }
+ else
+ {
+ names = 1; /* But loop once through names */
}
self = getpid ();
found = 0;
@@ -184,6 +198,54 @@ kill_all (int signal, int names, char **
}
for (i = 0; i < pids; i++)
{
+ /* Match by UID */
+ if (uid != NULL)
+ {
+ if (asprintf (&path, PROC_BASE "/%d/status", pid_table[i]) < 0)
+ {
+ continue;
+ }
+ if (!(file = fopen (path, "r")))
+ {
+ free (path);
+ continue;
+ }
+ free (path);
+ rc = 0;
+ while (rc == 0)
+ {
+ if ((rc = (int)fgets(ps_buffer, ps_buffer_size, file)) != EOF)
+ {
+ rc = sscanf (ps_buffer, "Uid:\t%d", &ps_uid);
+ }
+ }
+ (void) fclose(file);
+ if (rc == EOF)
+ {
+ fprintf(stderr, _("Cannot get UID from process status\n"));
+ exit (1);
+ }
+ if (*uid != ps_uid)
+ {
+ continue;
+ }
+ }
+#ifdef WITH_SELINUX
+ /* Match by context */
+ if (context_regex != NULL)
+ {
+ if (getpidcon(pid_table[i], &ps_context) < 0)
+ {
+ continue;
+ }
+ if (regexec (context_regex, (const char *)ps_context, 0, NULL, 0) != 0)
+ {
+ freecon(ps_context);
+ continue;
+ }
+ freecon(ps_context);
+ }
+#endif /*WITH_SELINUX*/
if (asprintf (&path, PROC_BASE "/%d/stat", pid_table[i]) < 0)
continue;
if (!(file = fopen (path, "r")))
@@ -262,60 +324,40 @@ kill_all (int signal, int names, char **
for (j = 0; j < names; j++)
{
pid_t id;
-
- if (!sts[j].st_dev)
+ if (!nameless)
{
- if (length != COMM_LEN - 1 || name_len[j] < COMM_LEN - 1)
- {
- if (ignore_case == 1)
- {
- if (strcasecmp (namelist[j], comm))
+ if (!sts[j].st_dev)
+ {
+ if (length != COMM_LEN - 1 || name_len[j] < COMM_LEN - 1)
+ {
+ if (ignore_case == 1)
+ {
+ if (strcasecmp (namelist[j], comm))
+ continue;
+ }
+ else
+ {
+ if (strcmp(namelist[j], comm))
+ continue;
+ }
+ }
+ else if (got_long ? strcmp (namelist[j], command) :
+ strncmp (namelist[j], comm, COMM_LEN - 1))
continue;
- }
- else
- {
- if (strcmp(namelist[j], comm))
+ }
+ else
+ {
+ if (asprintf (&path, PROC_BASE "/%d/exe", pid_table[i]) < 0)
continue;
- }
- }
- else if (got_long ? strcmp (namelist[j], command) :
- strncmp (namelist[j], comm, COMM_LEN - 1))
- continue;
-#ifdef WITH_SELINUX
- if ( scontext != NULL ) {
- if ( getpidcon(pid_table[i], &lcontext) < 0 )
- continue;
- if (strcmp(lcontext,scontext)!=0) {
- freecon(lcontext);
- continue;
- }
- freecon(lcontext);
- }
-#endif /*WITH_SELINUX*/
- }
- else
- {
- if (asprintf (&path, PROC_BASE "/%d/exe", pid_table[i]) < 0)
- continue;
- if (stat (path, &st) < 0) {
- free (path);
+ if (stat (path, &st) < 0) {
+ free (path);
+ continue;
+ }
+ free (path);
+ if (sts[j].st_dev != st.st_dev || sts[j].st_ino != st.st_ino)
continue;
- }
- free (path);
-#ifdef WITH_SELINUX
- if ( scontext != NULL ) {
- if ( getpidcon(pid_table[i], &lcontext) < 0 )
- continue;
- if (strcmp(lcontext,scontext)!=0) {
- freecon(lcontext);
- continue;
- }
- freecon(lcontext);
- }
-#endif /*WITH_SELINUX*/
- if (sts[j].st_dev != st.st_dev || sts[j].st_ino != st.st_ino)
- continue;
+ }
}
if (!process_group)
id = pid_table[i];
@@ -360,16 +402,25 @@ kill_all (int signal, int names, char **
}
if (empty)
{
- fprintf (stderr, _("%s is empty (not mounted ?)\n"), PROC_BASE);
- exit (1);
+ if (pids == 0)
+ {
+ fprintf (stderr, _("%s is empty (not mounted ?)\n"), PROC_BASE);
+ exit (1);
+ }
+ else
+ {
+ fprintf (stderr, _("Warning: No processes matched search criteria\n"));
+ exit(1);
+ }
}
- if (!quiet && !pidof)
+ if (!quiet && !pidof && !nameless)
for (i = 0; i < names; i++)
if (!(found & (1 << i)))
fprintf (stderr, _("%s: no process killed\n"), namelist[i]);
if (pidof)
putchar ('\n');
- error = found == ((1 << (names - 1)) | ((1 << (names - 1)) - 1)) ? 0 : 1;
+ /* If it gets this far and is nameless, at least one process matched. */
+ error = found == (((1 << (names - 1)) | ((1 << (names - 1)) - 1)) || nameless) ? 0 : 1;
/*
* We scan all (supposedly) killed processes every second to detect dead
* processes as soon as possible in order to limit problems of race with
@@ -410,12 +461,26 @@ static void
usage_killall (void)
{
#ifdef WITH_SELINUX
- fprintf(stderr, _(
- "Usage: killall [-Z CONTEXT] [ -egiqvw ] [ -SIGNAL ] NAME...\n"));
+ fprintf(stderr, _(
+ "Usage: killall [-Z CONTEXT] [-u USERID] [-egiqvw] [-SIGNAL] NAME...\n"));
+ fprintf(stderr, _(
+ " killall -l, --list\n"
+ " killall -V, --version\n\n"
+ " -e,--exact require exact match for very long names\n"
+ " -I,--ignore-case case insensitive process name match\n"
+ " -g,--process-group kill process group instead of process\n"
+ " -i,--interactive ask for confirmation before killing\n"
+ " -l,--list list all known signal names\n"
+ " -q,--quiet don't print complaints\n"
+ " -s,--signal SIGNAL send this signal instead of SIGTERM\n"
+ " -u,--user USER kill only process(es) running as USER\n"
+ " -v,--verbose report if the signal was successfully sent\n"
+ " -V,--version display version information\n"
+ " -w,--wait wait for processes to die\n"
+ " -Z,--context REGEX kill only process(es) whose SELinux context matches REGEX\n\n"));
#else /*WITH_SELINUX*/
fprintf(stderr, _(
"Usage: killall [OPTIONS]... [--] NAME...\n"));
-#endif /*WITH_SELINUX*/
fprintf(stderr, _(
" killall -l, --list\n"
" killall -V, --version\n\n"
@@ -426,13 +491,10 @@ usage_killall (void)
" -l,--list list all known signal names\n"
" -q,--quiet don't print complaints\n"
" -s,--signal SIGNAL send this signal instead of SIGTERM\n"
+ " -u,--user USER kill only process(es) running as USER\n"
" -v,--verbose report if the signal was successfully sent\n"
" -V,--version display version information\n"
" -w,--wait wait for processes to die\n\n"));
-#ifdef WITH_SELINUX
- fprintf(stderr, _(
- " -Z,--context CONTEXT kill only process(es) having context\n"
- " (must precede other arguments)"));
#endif /*WITH_SELINUX*/
}
@@ -466,7 +528,13 @@ main (int argc, char **argv)
int sig_num;
int optc;
int myoptind;
+ uid_t uid;
+ struct passwd *pwent;
//int optsig = 0;
+#ifdef WITH_SELINUX
+ int rc;
+ regex_t context_regex;
+#endif /*WITH_SELINUX*/
struct option options[] = {
{"exact", 0, NULL, 'e'},
@@ -476,6 +544,7 @@ main (int argc, char **argv)
{"list-signals", 0, NULL, 'l'},
{"quiet", 0, NULL, 'q'},
{"signal", 1, NULL, 's'},
+ {"user", 1, NULL, 'u'},
{"verbose", 0, NULL, 'v'},
{"wait", 0, NULL, 'w'},
#ifdef WITH_SELINUX
@@ -486,8 +555,6 @@ main (int argc, char **argv)
#ifdef WITH_SELINUX
security_context_t scontext = NULL;
-
- if ( argc < 2 ) usage(); /* do the obvious thing... */
#endif /*WITH_SELINUX*/
name = strrchr (*argv, '/');
@@ -507,9 +574,9 @@ main (int argc, char **argv)
opterr = 0;
#ifdef WITH_SELINUX
- while ( (optc = getopt_long_only(argc,argv,"egilqs:vwZ:VI",options,NULL)) != EOF) {
+ while ( (optc = getopt_long_only(argc,argv,"egilqs:u:vwZ:VI",options,NULL)) != EOF) {
#else
- while ( (optc = getopt_long_only(argc,argv,"egilqs:vwVI",options,NULL)) != EOF) {
+ while ( (optc = getopt_long_only(argc,argv,"egilqs:u:vwVI",options,NULL)) != EOF) {
#endif
switch (optc) {
case 'e':
@@ -537,6 +604,16 @@ main (int argc, char **argv)
case 's':
sig_num = get_signal (optarg, "killall");
break;
+ case 'u':
+ pwent = getpwnam(optarg);
+ if (pwent != NULL) {
+ uid = pwent->pw_uid;
+ byuser = 1;
+ } else {
+ fprintf (stderr, _("Cannot find user\n"));
+ exit (1);
+ }
+ break;
case 'v':
if (pidof)
usage();
@@ -556,13 +633,25 @@ main (int argc, char **argv)
break;
#ifdef WITH_SELINUX
case 'Z':
- if (is_selinux_enabled()>0)
- scontext=optarg;
- else
- fprintf(stderr, "Warning: -Z (--context) ignored. Requires an SELinux enabled kernel\n");
+ if (is_selinux_enabled() > 0) {
+ scontext = optarg;
+ if (regcomp(&context_regex, scontext, REG_EXTENDED|REG_NOSUB) != 0) {
+ fprintf(stderr, _("Bad regular expression\n"));
+ exit (1);
+ }
+ } else {
+ fprintf(stderr, _("Warning: -Z (--context) ignored. Requires an SELinux enabled kernel\n"));
+ }
break;
#endif /*WITH_SELINUX*/
case '?':
+#ifdef WITH_SELINUX
+ /* Special case the 'Z' option--it's the only uppercase opt with
+ * an optarg. Otherwise, code below confuses it with a signal. */
+ if (strncmp(argv[optind-1], "-Z", 32) == 0) {
+ usage();
+ }
+#endif /*WITH_SELINUX*/
/* Signal names are in uppercase, so check to see if the argv
* is upper case */
if (argv[optind-1][1] >= 'A' && argv[optind-1][1] <= 'Z') {
@@ -579,7 +668,11 @@ main (int argc, char **argv)
}
}
myoptind = optind;
- if (argc - myoptind < 1)
+#ifdef WITH_SELINUX
+ if ((argc - myoptind < 1) && (byuser == 0) && (scontext == NULL))
+#else
+ if ((argc - myoptind < 1) && (byuser == 0))
+#endif /*WITH_SELINUX*/
usage();
if (argc - myoptind > MAX_NAMES + 1)
@@ -590,8 +683,16 @@ main (int argc, char **argv)
argv = argv + myoptind;
/*printf("sending signal %d to procs\n", sig_num);*/
#ifdef WITH_SELINUX
- return kill_all(sig_num,argc - myoptind, argv, scontext);
+ rc = kill_all(sig_num,
+ argc - myoptind,
+ argv,
+ ((byuser == 0) ? NULL : &uid),
+ ((scontext == NULL) ? NULL : &context_regex));
+ if (scontext != NULL) {
+ regfree(&context_regex);
+ }
+ return rc;
#else /*WITH_SELINUX*/
- return kill_all(sig_num,argc - myoptind, argv );
+ return kill_all(sig_num, argc - myoptind, argv, ((byuser == 0) ? NULL : &uid));
#endif /*WITH_SELINUX*/
}
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [redhat-lspp] [RFC][PATCH] killall context regex and userid matching
2005-09-01 18:56 [RFC][PATCH] killall context regex and userid matching ltcgcw
@ 2005-09-01 21:10 ` Daniel J Walsh
2005-09-02 15:03 ` Stephen Smalley
1 sibling, 0 replies; 3+ messages in thread
From: Daniel J Walsh @ 2005-09-01 21:10 UTC (permalink / raw)
To: ltcgcw; +Cc: SELinux, redhat-lspp
[-- Attachment #1: Type: text/plain, Size: 660 bytes --]
ltcgcw@us.ibm.com wrote:
>Please find a patch to psmisc attached. It adds these features to killall:
> - regular expression SELinux context matching
> - userid matching
> - process names now optional when matching by either context or userid
> - most fprintf() strings now gettext-ized
> - help text no longer split up by #ifdef; missing newline added
> - manpage updates
>
>The patch applies to the psmisc CVS tree, current as of today. I will
>submit it to the psmisc maintainer once I incorporate comments received on
>this list. It might be useful to add something similar to skill and snice.
>
>
>
Updated patch to apply to psmisc-21.5
--
[-- Attachment #2: psmisc-21.5-selinux-user.patch --]
[-- Type: text/x-patch, Size: 14333 bytes --]
--- psmisc-21.5/src/killall.c.selinux-user 2005-09-01 16:58:13.000000000 -0400
+++ psmisc-21.5/src/killall.c 2005-09-01 17:00:44.000000000 -0400
@@ -22,7 +22,9 @@
#include <sys/stat.h>
#include <getopt.h>
#ifdef WITH_SELINUX
+#include <regex.h>
#include <selinux/selinux.h>
+#include <pwd.h>
#endif /*WITH_SELINUX*/
#ifdef ENABLE_NLS
#include <libintl.h>
@@ -42,7 +44,7 @@
static int verbose = 0, exact = 0, interactive = 0,
quiet = 0, wait_until_dead = 0, process_group = 0,
- ignore_case = 0, pidof;
+ ignore_case = 0, byuser = 0, pidof;
static int
ask (char *name, pid_t pid)
@@ -69,17 +71,17 @@
#ifdef WITH_SELINUX
static int
-kill_all(int signal, int names, char **namelist, security_context_t scontext )
+kill_all(int signal, int names, char **namelist, uid_t *uid, regex_t *context_regex)
#else /*WITH_SELINUX*/
static int
-kill_all (int signal, int names, char **namelist)
+kill_all (int signal, int names, char **namelist, uid_t *uid)
#endif /*WITH_SELINUX*/
{
DIR *dir;
struct dirent *de;
FILE *file;
struct stat st, sts[MAX_NAMES];
- int *name_len;
+ int *name_len=NULL;
char *path, comm[COMM_LEN];
char *command_buf;
char *command;
@@ -88,30 +90,45 @@
int empty, i, j, okay, length, got_long, error;
int pids, max_pids, pids_killed;
unsigned long found;
+ uid_t ps_uid = 0;
+ const int ps_buffer_size = 80;
+ char ps_buffer[ps_buffer_size];
+ int rc = 0;
#ifdef WITH_SELINUX
+ int nameless = ((names == 0) && ((uid != NULL) || (context_regex != NULL)));
+ security_context_t ps_context = NULL;
+#else
+ int nameless = (names == 0) && (uid != NULL);
security_context_t lcontext=NULL;
if ( names == 0 || ! namelist ) exit( 1 ); /* do the obvious thing...*/
#endif /*WITH_SELINUX*/
- if (!(name_len = malloc (sizeof (int) * names)))
- {
- perror ("malloc");
- exit (1);
- }
- for (i = 0; i < names; i++) {
- if (!strchr (namelist[i], '/'))
+ if (!nameless)
+ {
+ if (!(name_len = malloc (sizeof (int) * names)))
{
- sts[i].st_dev = 0;
- name_len[i] = strlen (namelist[i]);
+ perror ("malloc");
+ exit (1);
+ }
+ for (i = 0; i < names; i++) {
+ if (!strchr (namelist[i], '/'))
+ {
+ sts[i].st_dev = 0;
+ name_len[i] = strlen (namelist[i]);
+ }
+ else {
+ if (stat (namelist[i], &sts[i]) < 0)
+ {
+ perror (namelist[i]);
+ exit (1);
+ }
}
- else {
- if (stat (namelist[i], &sts[i]) < 0)
- {
- perror (namelist[i]);
- exit (1);
- }
}
+ }
+ else
+ {
+ names = 1; /* But loop once through names */
}
self = getpid ();
found = 0;
@@ -165,6 +182,54 @@
}
for (i = 0; i < pids; i++)
{
+ /* Match by UID */
+ if (uid != NULL)
+ {
+ if (asprintf (&path, PROC_BASE "/%d/status", pid_table[i]) < 0)
+ {
+ continue;
+ }
+ if (!(file = fopen (path, "r")))
+ {
+ free (path);
+ continue;
+ }
+ free (path);
+ rc = 0;
+ while (rc == 0)
+ {
+ if ((rc = (int)fgets(ps_buffer, ps_buffer_size, file)) != EOF)
+ {
+ rc = sscanf (ps_buffer, "Uid:\t%d", &ps_uid);
+ }
+ }
+ (void) fclose(file);
+ if (rc == EOF)
+ {
+ fprintf(stderr, _("Cannot get UID from process status\n"));
+ exit (1);
+ }
+ if (*uid != ps_uid)
+ {
+ continue;
+ }
+ }
+#ifdef WITH_SELINUX
+ /* Match by context */
+ if (context_regex != NULL)
+ {
+ if (getpidcon(pid_table[i], &ps_context) < 0)
+ {
+ continue;
+ }
+ if (regexec (context_regex, (const char *)ps_context, 0, NULL, 0) != 0)
+ {
+ freecon(ps_context);
+ continue;
+ }
+ freecon(ps_context);
+ }
+#endif /*WITH_SELINUX*/
if (asprintf (&path, PROC_BASE "/%d/stat", pid_table[i]) < 0)
continue;
if (!(file = fopen (path, "r")))
@@ -244,60 +309,40 @@
{
pid_t id;
- if (!sts[j].st_dev)
- {
- if (length != COMM_LEN - 1 || name_len[j] < COMM_LEN - 1)
- {
- if (ignore_case == 1)
- {
- if (strcasecmp (namelist[j], comm))
+ if (!nameless)
+ {
+ if (!sts[j].st_dev)
+ {
+ if (length != COMM_LEN - 1 || name_len[j] < COMM_LEN - 1)
+ {
+ if (ignore_case == 1)
+ {
+ if (strcasecmp (namelist[j], comm))
+ continue;
+ }
+ else
+ {
+ if (strcmp(namelist[j], comm))
+ continue;
+ }
+ }
+ else if (got_long ? strcmp (namelist[j], command) :
+ strncmp (namelist[j], comm, COMM_LEN - 1))
continue;
- }
- else
- {
- if (strcmp(namelist[j], comm))
+ }
+ else
+ {
+ if (asprintf (&path, PROC_BASE "/%d/exe", pid_table[i]) < 0)
continue;
- }
- }
- else if (got_long ? strcmp (namelist[j], command) :
- strncmp (namelist[j], comm, COMM_LEN - 1))
- continue;
-#ifdef WITH_SELINUX
- if ( scontext != NULL ) {
- if ( getpidcon(pid_table[i], &lcontext) < 0 )
- continue;
- if (strcmp(lcontext,scontext)!=0) {
- freecon(lcontext);
- continue;
- }
- freecon(lcontext);
- }
-#endif /*WITH_SELINUX*/
- }
- else
- {
- if (asprintf (&path, PROC_BASE "/%d/exe", pid_table[i]) < 0)
- continue;
- if (stat (path, &st) < 0) {
+ if (stat (path, &st) < 0) {
free (path);
continue;
- }
- free (path);
-#ifdef WITH_SELINUX
- if ( scontext != NULL ) {
- if ( getpidcon(pid_table[i], &lcontext) < 0 )
- continue;
- if (strcmp(lcontext,scontext)!=0) {
- freecon(lcontext);
- continue;
- }
- freecon(lcontext);
- }
-#endif /*WITH_SELINUX*/
-
- if (sts[j].st_dev != st.st_dev || sts[j].st_ino != st.st_ino)
- continue;
+ }
+ free (path);
+ if (sts[j].st_dev != st.st_dev || sts[j].st_ino != st.st_ino)
+ continue;
+ }
}
if (!process_group)
id = pid_table[i];
@@ -342,16 +387,25 @@
}
if (empty)
{
- fprintf (stderr, _("%s is empty (not mounted ?)\n"), PROC_BASE);
- exit (1);
+ if (pids == 0)
+ {
+ fprintf (stderr, _("%s is empty (not mounted ?)\n"), PROC_BASE);
+ exit (1);
+ }
+ else
+ {
+ fprintf (stderr, _("Warning: No processes matched search criteria\n"));
+ exit(1);
+ }
}
- if (!quiet && !pidof)
+ if (!quiet && !pidof && !nameless)
for (i = 0; i < names; i++)
if (!(found & (1 << i)))
fprintf (stderr, _("%s: no process killed\n"), namelist[i]);
if (pidof)
putchar ('\n');
- error = found == ((1 << (names - 1)) | ((1 << (names - 1)) - 1)) ? 0 : 1;
+ /* If it gets this far and is nameless, at least one process matched. */
+ error = found == (((1 << (names - 1)) | ((1 << (names - 1)) - 1)) || nameless) ? 0 : 1;
/*
* We scan all (supposedly) killed processes every second to detect dead
* processes as soon as possible in order to limit problems of race with
@@ -392,15 +446,12 @@
usage_killall (void)
{
#ifdef WITH_SELINUX
- fprintf(stderr,"Usage: killall [-Z context] [ -egiqvw ] [ -signal ] name ...\n");
-#else /*WITH_SELINUX*/
+ fprintf(stderr,"Usage: killall [-Z context] [ -u USERID ] [ -eIgilqsvVw ] [ -signal ] name ...\n");
+#else
fprintf (stderr, "usage: killall [ OPTIONS ] [ -- ] name ...\n");
#endif /*WITH_SELINUX*/
fprintf (stderr, " killall -l, --list\n");
fprintf (stderr, " killall -V --version\n\n");
-#ifdef WITH_SELINUX
- fprintf (stderr, " -Z,--context kill only process(es) having scontext\n");
-#endif /*WITH_SELINUX*/
fprintf (stderr, " -e,--exact require exact match for very long names\n");
fprintf (stderr, " -I,--ignore-case- case insensitive process name match\n");
fprintf (stderr, " -g,--process-group kill process group instead of process\n");
@@ -408,9 +459,15 @@
fprintf (stderr, " -l,--list list all known signal names\n");
fprintf (stderr, " -q,--quiet don't print complaints\n");
fprintf (stderr, " -s,--signal send signal instead of SIGTERM\n");
+#ifdef WITH_SELINUX
+ fprintf (stderr, " -u,--user USER kill only process(es) running as USER\n");
+#endif
fprintf (stderr, " -v,--verbose report if the signal was successfully sent\n");
fprintf (stderr, " -V,--version display version information\n");
fprintf (stderr, " -w,--wait wait for processes to die\n\n");
+#ifdef WITH_SELINUX
+ fprintf (stderr, " -Z,--context kill only process(es) having scontext\n");
+#endif
}
@@ -441,7 +498,13 @@
int sig_num;
int optc;
int myoptind;
+ uid_t uid;
+ struct passwd *pwent;
//int optsig = 0;
+#ifdef WITH_SELINUX
+ int rc;
+ regex_t context_regex;
+#endif /*WITH_SELINUX*/
struct option options[] = {
{"exact", 0, NULL, 'e'},
@@ -451,6 +514,7 @@
{"list-signals", 0, NULL, 'l'},
{"quiet", 0, NULL, 'q'},
{"signal", 1, NULL, 's'},
+ {"user", 1, NULL, 'u'},
{"verbose", 0, NULL, 'v'},
{"wait", 0, NULL, 'w'},
#ifdef WITH_SELINUX
@@ -462,7 +526,6 @@
#ifdef WITH_SELINUX
security_context_t scontext = NULL;
- if ( argc < 2 ) usage(); /* do the obvious thing... */
#endif /*WITH_SELINUX*/
name = strrchr (*argv, '/');
@@ -482,7 +545,7 @@
opterr = 0;
#ifdef WITH_SELINUX
- while ( (optc = getopt_long_only(argc,argv,"egilqs:vwVIZ",options,NULL)) != EOF) {
+ while ( (optc = getopt_long_only(argc,argv,"egilqs:u:vwVIZ:",options,NULL)) != EOF) {
#else
while ( (optc = getopt_long_only(argc,argv,"egilqs:vwVI",options,NULL)) != EOF) {
#endif
@@ -512,6 +575,16 @@
case 's':
sig_num = get_signal (optarg, "killall");
break;
+ case 'u':
+ pwent = getpwnam(optarg);
+ if (pwent != NULL) {
+ uid = pwent->pw_uid;
+ byuser = 1;
+ } else {
+ fprintf (stderr, _("Cannot find user\n"));
+ exit (1);
+ }
+ break;
case 'v':
if (pidof)
usage();
@@ -531,14 +604,25 @@
break;
#ifdef WITH_SELINUX
case 'Z':
- if( is_selinux_enabled()>0)
+ if( is_selinux_enabled()>0) {
scontext=optarg;
- else
+ if (regcomp(&context_regex, scontext, REG_EXTENDED|REG_NOSUB) != 0) {
+ fprintf(stderr, _("Bad regular expression\n"));
+ exit (1);
+ }
+ } else {
fprintf(stderr, "Warning: -Z (--context) ignored. Requires an SELinux enabled kernel\n");
+ }
break;
#endif /*WITH_SELINUX*/
case '?':
- /* Signal names are in uppercase, so check to see if the argv
+#ifdef WITH_SELINUX
+ /* Special case the 'Z' option--it's the only uppercase opt with
+ * an optarg. Otherwise, code below confuses it with a signal. */
+ if (strncmp(argv[optind-1], "-Z", 32) == 0) {
+ usage();
+ }
+#endif /*WITH_SELINUX*/ /* Signal names are in uppercase, so check to see if the argv
* is upper case */
if (argv[optind-1][1] >= 'A' && argv[optind-1][1] <= 'Z')
sig_num = get_signal (argv[optind-1]+1, "killall");
@@ -558,7 +642,11 @@
}
*/
myoptind = optind;
- if (argc - myoptind < 1)
+#ifdef WITH_SELINUX
+ if ((argc - myoptind < 1) && (byuser == 0) && (scontext == NULL))
+#else
+ if ((argc - myoptind < 1) && (byuser == 0))
+#endif /*WITH_SELINUX*/
usage();
if (argc - myoptind > MAX_NAMES + 1)
@@ -569,8 +657,16 @@
argv = argv + myoptind;
/*printf("sending signal %d to procs\n", sig_num);*/
#ifdef WITH_SELINUX
- return kill_all(sig_num,argc - myoptind, argv, scontext);
+ rc = kill_all(sig_num,
+ argc - myoptind,
+ argv,
+ ((byuser == 0) ? NULL : &uid),
+ ((scontext == NULL) ? NULL : &context_regex));
+ if (scontext != NULL) {
+ regfree(&context_regex);
+ }
+ return rc;
#else /*WITH_SELINUX*/
- return kill_all(sig_num,argc - myoptind, argv );
+ return kill_all(sig_num, argc - myoptind, argv, ((byuser == 0) ? NULL : &uid));
#endif /*WITH_SELINUX*/
}
--- psmisc-21.5/doc/killall.1.selinux-user 2005-09-01 16:58:13.000000000 -0400
+++ psmisc-21.5/doc/killall.1 2005-09-01 16:58:13.000000000 -0400
@@ -4,13 +4,16 @@
.SH SYNOPSIS
.ad l
.B killall
-.RB [ \-c , \-\-context ]
+.RB [ \-Z , \-\-context
+.IR regex ]
.RB [ \-e , --exact ]
.RB [ \-g , \-\-process-group ]
.RB [ \-i , \-\-interactive ]
.RB [ \-q , \-\-quiet ]
.RB [ \-s , \-\-signal
.IR signal ]
+.RB [ \-u , \-\-user
+.IR user ]
.RB [ \-v , \-\-verbose ]
.RB [ \-w , \-\-wait ]
.RB [ \-V, \-\-version ]
@@ -35,7 +38,9 @@
particular file will be selected for killing, independent of their name.
.PP
\fBkillall\fP returns a zero return code if at least one process has been
-killed for each listed command. \fBkillall\fP returns non-zero otherwise.
+killed for each listed command, or no commands were listed and at least
+one process matched the -u and -Z search criteria. \fBkillall\fP returns
+non-zero otherwise.
.PP
A \fBkillall\fP process never kills itself (but may kill other \fBkillall\fP
processes).
@@ -59,6 +64,8 @@
List all known signal names.
.IP "\fB\-q\fP, \fB\-\-quiet\fP"
Do not complain if no processes were killed.
+.IP "\fB\-u\fP, \fB\-\-user\fP"
+Kill only processes the specified user owns. Command names are optional.
.IP "\fB\-v\fP, \fB\-\-verbose\fP"
Report if the signal was successfully sent.
.IP "\fB\-V\fP, \fB\-\-version\fP"
@@ -68,9 +75,9 @@
any of the killed processes still exist and only returns if none are left.
Note that \fBkillall\fP may wait forever if the signal was ignored, had no
effect, or if the process stays in zombie state.
-.IP \fB\-Z\fP
-(SELinux Only) Specify security context: kill only processes with given security context.
-Must precede other arguments on the command line.
+.IP "\fB\-Z\fP, \fB\-\-context\fP"
+(SELinux Only) Kill only processes having a security context that matches the
+given extended regular expression. Command names are optional.
.SH FILES
.nf
/proc location of the proc file system
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [RFC][PATCH] killall context regex and userid matching
2005-09-01 18:56 [RFC][PATCH] killall context regex and userid matching ltcgcw
2005-09-01 21:10 ` [redhat-lspp] " Daniel J Walsh
@ 2005-09-02 15:03 ` Stephen Smalley
1 sibling, 0 replies; 3+ messages in thread
From: Stephen Smalley @ 2005-09-02 15:03 UTC (permalink / raw)
To: ltcgcw; +Cc: SELinux, redhat-lspp
On Thu, 2005-09-01 at 13:56 -0500, ltcgcw@us.ibm.com wrote:
> Please find a patch to psmisc attached. It adds these features to killall:
> - regular expression SELinux context matching
> - userid matching
> - process names now optional when matching by either context or userid
> - most fprintf() strings now gettext-ized
> - help text no longer split up by #ifdef; missing newline added
> - manpage updates
>
> The patch applies to the psmisc CVS tree, current as of today. I will
> submit it to the psmisc maintainer once I incorporate comments received on
> this list. It might be useful to add something similar to skill and snice.
With regard to regex matching, one thing to watch out for is whether any
of the characters in a security context might have special meaning in a
regex. For example, the extended syntax for MLS levels introduced by
TCS uses a dot (.) notation as a shorthand way of expressing category
sets with contiguous sets of categories, e.g. c0.c127. Hence,
killall -Z :s0:c0.c3,c7
will match both :s0:c0,c3,c7 and :s0:c0.c3,c7 (i.e. :s0:c0,c1,c2,c3,c7).
You'd have to do something like:
killall -Z ':s0:c0\.c3,c7'
to protect the dot from regex interpretation.
You may want to note this in the documentation.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2005-09-02 15:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-01 18:56 [RFC][PATCH] killall context regex and userid matching ltcgcw
2005-09-01 21:10 ` [redhat-lspp] " Daniel J Walsh
2005-09-02 15:03 ` Stephen Smalley
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.