Problem - rdistd can dump core when a distfile contains cmdspecial.
For example:
# mkdir /tmp/rdist.demo && cd /tmp/rdist.demo
# cat /root/Distfile.demo
/usr/bin -> localhost
install /tmp/rdist.demo/files ;
cmdspecial "echo The files were: ${FILES:-*-empty-*} > DONE" ;
# rdist -f /root/Distfile.demo
localhost: updating host localhost
... [deleted lines]
localhost: cmdspecial "echo The files were: ${FILES:-*-empty-*} > DONE"
localhost: worm: REMOTE ERROR: shell returned 32512
... [deleted lines]
localhost: updating of localhost finished
# ls
files rdistd.core
This occurs since the buffer cmd in dospecial() [rdistd/server.c] overflows.
The purpose of this buffer is to store the string 'FILES=...; <cmd>" which
is passed to an invocation of execl() in runcommand() [rdist/common.c].
The actual invocation is 'sh -c <FILES=...;<cmd>', so maybe a few extra
characters should get lopped off the buffer to prevent an overflow in
kern/kern_exec.c...
The patch (hack?) for this is simple (noting that the preconditions of
strunvis() are not explicitly checked...):
Index: server.c
===================================================================
RCS file: /cvs/src/usr.bin/rdistd/server.c,v
retrieving revision 1.33
diff -u -p -r1.33 server.c
--- server.c 12 Jul 2014 03:10:03 -0000 1.33
+++ server.c 8 Nov 2014 02:57:37 -0000
@@ -462,7 +462,7 @@ clean(char *cp)
static void
dospecial(char *xcmd)
{
- char cmd[BUFSIZ];
+ char cmd[ARG_MAX];
if (DECODE(cmd, xcmd) == -1) {
error("dospecial: Cannot decode command.");
return;
However, the fundamental mechanism of passing the full list of updated files
via the environment variable FILES is broken - a long list of updated files
will still overflow this buffer. It's not a real solution.
The patch below changes the behaviour of cmdspecial in a distfile, allowing
'-'
to be used in the optional name list to indicate that the list of updated
filenames should not be put into the FILES environment variable.
This patch meets my needs, but I can see the value of having the list of
updated
files available (just not via the environment). If there are some good ideas
and consensus on what should be done I'm willing to code them up. For
example,
to write the list of updated files into a temporary file and pass the name
of
the file via the FILELIST environemnt variable, or to pipe the contents of
the
file list to stdin...).
Let me know and I'll do it.
Index: client.c
===================================================================
RCS file: /cvs/src/usr.bin/rdist/client.c,v
retrieving revision 1.31
diff -u -p -r1.31 client.c
--- client.c 12 Jul 2014 03:48:04 -0000 1.31
+++ client.c 8 Nov 2014 03:00:06 -0000
@@ -250,17 +250,19 @@ runcmdspecial(struct cmd *cmd, opt_t opt
message(MT_CHANGE, "cmdspecial \"%s\"", sc->sc_name);
if (IS_ON(opts, DO_VERIFY))
continue;
- /* Send all the file names */
- for (f = updfilelist; f != NULL; f = f->n_next) {
- if (first) {
- (void) sendcmd(C_CMDSPECIAL, NULL);
+ if (sc->sc_args != nofilelist) {
+ /* Send all the file names */
+ for (f = updfilelist; f != NULL; f = f->n_next) {
+ if (first) {
+ (void) sendcmd(C_CMDSPECIAL, NULL);
+ if (response() < 0)
+ return;
+ first = FALSE;
+ }
+ (void) sendcmd(RC_FILE, "%s", f->n_name);
if (response() < 0)
return;
- first = FALSE;
}
- (void) sendcmd(RC_FILE, "%s", f->n_name);
- if (response() < 0)
- return;
}
if (first) {
(void) sendcmd(C_CMDSPECIAL, NULL);
Index: defs.h
===================================================================
RCS file: /cvs/src/usr.bin/rdist/defs.h,v
retrieving revision 1.31
diff -u -p -r1.31 defs.h
--- defs.h 12 Jul 2014 03:48:04 -0000 1.31
+++ defs.h 8 Nov 2014 03:00:07 -0000
@@ -280,6 +280,7 @@ extern struct passwd *pw; /* pointer t
extern char defowner[64]; /* Default owner */
extern char defgroup[64]; /* Default group */
extern volatile sig_atomic_t contimedout; /* Connection timed out */
+extern struct namelist *nofilelist; /* Sentinel for explicit no file
list */
/*
* Our own declarations.
Index: docmd.c
===================================================================
RCS file: /cvs/src/usr.bin/rdist/docmd.c,v
retrieving revision 1.31
diff -u -p -r1.31 docmd.c
--- docmd.c 12 Jul 2014 03:48:04 -0000 1.31
+++ docmd.c 8 Nov 2014 03:00:08 -0000
@@ -46,6 +46,10 @@ struct namelist *filelist; /* li
extern struct cmd *cmds; /* Initialized by yyparse() */
time_t lastmod; /* Last modify time */
+/* Marker for cmdspecial - don't send FILES */
+static struct namelist _sentinel = { "no FILES", NULL, NULL };
+struct namelist *nofilelist = &_sentinel;
+
extern char target[BUFSIZ];
extern char *ptarget;
extern int activechildren;
Index: expand.c
===================================================================
RCS file: /cvs/src/usr.bin/rdist/expand.c,v
retrieving revision 1.14
diff -u -p -r1.14 expand.c
--- expand.c 5 Jul 2014 06:45:00 -0000 1.14
+++ expand.c 8 Nov 2014 03:00:09 -0000
@@ -98,7 +98,7 @@ addpath(int c)
}
/*
- * Take a list of names and expand any macros, etc.
+ * Take a list of names and expand any macros, etc. (except if nofilelist)
* wh = E_VARS if expanding variables.
* wh = E_SHELL if expanding shell characters.
* wh = E_TILDE if expanding `~'.
@@ -112,6 +112,9 @@ expand(struct namelist *list, int wh) /
struct namelist *nl, *prev;
int n;
char pathbuf[BUFSIZ];
+
+ if (nofilelist == list)
+ return list;
if (debug)
debugmsg(DM_CALL, "expand(%p, %d) start, list = %s",
Index: gram.y
===================================================================
RCS file: /cvs/src/usr.bin/rdist/gram.y,v
retrieving revision 1.11
diff -u -p -r1.11 gram.y
--- gram.y 7 Jun 2014 15:28:21 -0000 1.11
+++ gram.y 8 Nov 2014 03:00:09 -0000
@@ -218,6 +218,9 @@ opt_namelist: /* VOID */ = {
| namelist = {
$$ = $1;
}
+ | '-' = {
+ $$ = nofilelist;
+ }
;
%%
Index: rdist.1
===================================================================
RCS file: /cvs/src/usr.bin/rdist/rdist.1,v
retrieving revision 1.45
diff -u -p -r1.45 rdist.1
--- rdist.1 10 Jul 2014 14:29:27 -0000 1.45
+++ rdist.1 8 Nov 2014 03:00:11 -0000
@@ -499,8 +499,8 @@ format:
.It notify Ta \*(Ltname list\*(Gt Ta "" Ta ;
.It except Ta \*(Ltname list\*(Gt Ta "" Ta ;
.It except_pat Ta \*(Ltpattern list\*(Gt Ta "" Ta ;
-.It special Ta \*(Ltname list\*(Gt Ta string Ta ;
-.It cmdspecial Ta \*(Ltname list\*(Gt Ta string Ta ;
+.It special Ta \*(Ltopt name list\*(Gt Ta string Ta ;
+.It cmdspecial Ta \*(Ltopt name list\*(Gt Ta string Ta ;
.El
.Pp
The
@@ -603,7 +603,9 @@ command, except it is executed only when
instead of after each file is updated.
The list of files is placed in the
.Ev FILES
-environment variable.
+environment variable (except when
+.Ar opt name list
+is set to `-').
Each file name in
.Ev FILES
is separated by a
Index: rdist.c
===================================================================
RCS file: /cvs/src/usr.bin/rdist/rdist.c,v
retrieving revision 1.28
diff -u -p -r1.28 rdist.c
--- rdist.c 12 Jul 2014 03:32:00 -0000 1.28
+++ rdist.c 8 Nov 2014 03:00:11 -0000
@@ -302,9 +302,6 @@ opendist(char *distfile)
else if (access("Distfile", R_OK) == 0)
file = "Distfile";
} else {
- /*
- * Try to test to see if file is readable before running m4.
- */
if (access(distfile, R_OK) != 0)
fatalerr("%s: Cannot access file: %s.",
distfile, SYSERR);
Demo of the patched rdist:
# mkdir /tmp/rdist.demo && cd /tmp/rdist.demo
# cat /root/Distfile.demo2
/usr/bin -> localhost
install /tmp/rdist.demo/files ;
cmdspecial - "echo The files were: ${FILES:-*-empty-*} > DONE
# /home/mike/rdist/src/rdist/rdist -f /root/Distfile.demo2
localhost: updating host localhost
... [deleted lines]
# cat DONE
The files were: *-empty-*
(note - no core dump)
OK?