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
filesrdistd.core
This occurs since the buffer cmd in dospecial() [rdistd/server.c] overflows.
The purpose of this buffer is to store the string 'FILES=...; " which
is passed to an invocation of execl() in runcommand() [rdist/common.c].
The actual invocation is 'sh -c ', 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.c12 Jul 2014 03:10:03 -1.33
+++ server.c8 Nov 2014 02:57:37 -
@@ -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.c12 Jul 2014 03:48:04 -1.31
+++ client.c8 Nov 2014 03:00:06 -
@@ -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.h12 Jul 2014 03:48:04 -1.31
+++ defs.h8 Nov 2014 03:00:07 -
@@ -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.c12 Jul 2014 03:48:04 -1.31
+++ docmd.c8 Nov 2014 03:00:08 -
@@ -46,6 +46,10 @@ struct namelist *filelist;/* li
extern struct cmd *cmds;/* Initialized by yyparse() */
time_tlastmod;/* Last modify time */
+/* Marker for cmdspecial - don't send FILES */
+static struct namelist _sentinel = { "