It was pointed out[0] that ctags(1) uses some potentially dangerous
system(3) calls where user-supplied data is used with no sanity checking. Since ctags(1) is not setuid and is not likely to be used in a privileged situation, this is not a big deal. However, the fix is relatively easy and less ugly than the current code, let's be safe. (I'm sure there are about 2^134 other system(3) calls like this out there.) [0] On freebsd-security by Roman Bogorodskiy <bogorodskiy@inbox.ru> with subject "ctags(1) command execution vulnerability." MFC after: 3 days
This commit is contained in:
parent
1cbf549da4
commit
e075483771
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=129042
@ -44,11 +44,14 @@ static char sccsid[] = "@(#)ctags.c 8.4 (Berkeley) 2/7/95";
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <regex.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -94,7 +97,6 @@ main(int argc, char **argv)
|
|||||||
int exit_val; /* exit value */
|
int exit_val; /* exit value */
|
||||||
int step; /* step through args */
|
int step; /* step through args */
|
||||||
int ch; /* getopts char */
|
int ch; /* getopts char */
|
||||||
char *cmd;
|
|
||||||
|
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
|
|
||||||
@ -164,16 +166,38 @@ main(int argc, char **argv)
|
|||||||
put_entries(head);
|
put_entries(head);
|
||||||
else {
|
else {
|
||||||
if (uflag) {
|
if (uflag) {
|
||||||
|
FILE *oldf;
|
||||||
|
regex_t *regx;
|
||||||
|
|
||||||
|
if ((oldf = fopen(outfile, "r")) == NULL)
|
||||||
|
err(1, "opening %s", outfile);
|
||||||
|
if (unlink(outfile))
|
||||||
|
err(1, "unlinking %s", outfile);
|
||||||
|
if ((outf = fopen(outfile, "w")) == NULL)
|
||||||
|
err(1, "recreating %s", outfile);
|
||||||
|
if ((regx = calloc(argc, sizeof(regex_t))) == NULL)
|
||||||
|
err(1, "RE alloc");
|
||||||
for (step = 0; step < argc; step++) {
|
for (step = 0; step < argc; step++) {
|
||||||
(void)asprintf(&cmd,
|
(void)strcpy(lbuf, "\t");
|
||||||
"mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
|
(void)strlcat(lbuf, argv[step], LINE_MAX);
|
||||||
outfile, argv[step], outfile);
|
(void)strlcat(lbuf, "\t", LINE_MAX);
|
||||||
if (cmd == NULL)
|
if (regcomp(regx + step, lbuf,
|
||||||
err(1, "out of space");
|
REG_NOSPEC))
|
||||||
system(cmd);
|
warn("RE compilation failed");
|
||||||
free(cmd);
|
|
||||||
cmd = NULL;
|
|
||||||
}
|
}
|
||||||
|
nextline:
|
||||||
|
while (fgets(lbuf, LINE_MAX, oldf)) {
|
||||||
|
for (step = 0; step < argc; step++)
|
||||||
|
if (regexec(regx + step,
|
||||||
|
lbuf, 0, NULL, 0) == 0)
|
||||||
|
goto nextline;
|
||||||
|
fputs(lbuf, outf);
|
||||||
|
}
|
||||||
|
for (step = 0; step < argc; step++)
|
||||||
|
regfree(regx + step);
|
||||||
|
free(regx);
|
||||||
|
fclose(oldf);
|
||||||
|
fclose(outf);
|
||||||
++aflag;
|
++aflag;
|
||||||
}
|
}
|
||||||
if (!(outf = fopen(outfile, aflag ? "a" : "w")))
|
if (!(outf = fopen(outfile, aflag ? "a" : "w")))
|
||||||
@ -181,13 +205,18 @@ main(int argc, char **argv)
|
|||||||
put_entries(head);
|
put_entries(head);
|
||||||
(void)fclose(outf);
|
(void)fclose(outf);
|
||||||
if (uflag) {
|
if (uflag) {
|
||||||
(void)asprintf(&cmd, "sort -o %s %s",
|
pid_t pid;
|
||||||
outfile, outfile);
|
|
||||||
if (cmd == NULL)
|
if ((pid = fork()) == -1)
|
||||||
err(1, "out of space");
|
err(1, "fork failed");
|
||||||
system(cmd);
|
else if (pid == 0) {
|
||||||
free(cmd);
|
execlp("sort", "sort", "-o", outfile,
|
||||||
cmd = NULL;
|
outfile, NULL);
|
||||||
|
err(1, "exec of sort failed");
|
||||||
|
}
|
||||||
|
/* Just assume the sort went OK. The old code
|
||||||
|
did not do any checks either. */
|
||||||
|
(void)wait(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user