lpd: fix OOM vulnerability (was eating arbitrarily large commands)

This commit is contained in:
Denis Vlasenko 2008-03-24 00:04:42 +00:00
parent a79428998d
commit 0b6c6a9c9f
4 changed files with 33 additions and 19 deletions

View File

@ -529,7 +529,7 @@ extern char *reads(int fd, char *buf, size_t count);
// Read one line a-la fgets. Reads byte-by-byte. // Read one line a-la fgets. Reads byte-by-byte.
// Useful when it is important to not read ahead. // Useful when it is important to not read ahead.
// Bytes are appended to pfx (which must be malloced, or NULL). // Bytes are appended to pfx (which must be malloced, or NULL).
extern char *xmalloc_reads(int fd, char *pfx); extern char *xmalloc_reads(int fd, char *pfx, size_t *maxsz_p);
extern ssize_t read_close(int fd, void *buf, size_t count); extern ssize_t read_close(int fd, void *buf, size_t count);
extern ssize_t open_read_close(const char *filename, void *buf, size_t count); extern ssize_t open_read_close(const char *filename, void *buf, size_t count);
extern void *xmalloc_open_read_close(const char *filename, size_t *sizep); extern void *xmalloc_open_read_close(const char *filename, size_t *sizep);

View File

@ -152,13 +152,14 @@ char *reads(int fd, char *buffer, size_t size)
// Read one line a-la fgets. Reads byte-by-byte. // Read one line a-la fgets. Reads byte-by-byte.
// Useful when it is important to not read ahead. // Useful when it is important to not read ahead.
// Bytes are appended to pfx (which must be malloced, or NULL). // Bytes are appended to pfx (which must be malloced, or NULL).
char *xmalloc_reads(int fd, char *buf) char *xmalloc_reads(int fd, char *buf, size_t *maxsz_p)
{ {
char *p; char *p;
int sz = buf ? strlen(buf) : 0; size_t sz = buf ? strlen(buf) : 0;
size_t maxsz = maxsz_p ? *maxsz_p : MAXINT(size_t);
goto jump_in; goto jump_in;
while (1) { while (sz < maxsz) {
if (p - buf == sz) { if (p - buf == sz) {
jump_in: jump_in:
buf = xrealloc(buf, sz + 128); buf = xrealloc(buf, sz + 128);
@ -178,6 +179,8 @@ char *xmalloc_reads(int fd, char *buf)
p++; p++;
} }
*p++ = '\0'; *p++ = '\0';
if (maxsz_p)
*maxsz_p = p - buf - 1;
return xrealloc(buf, p - buf); return xrealloc(buf, p - buf);
} }

View File

@ -58,8 +58,6 @@
*/ */
#include "libbb.h" #include "libbb.h"
// TODO: xmalloc_reads is vulnerable to remote OOM attack!
// strip argument of bad chars // strip argument of bad chars
static char *sane(char *str) static char *sane(char *str)
{ {
@ -75,6 +73,21 @@ static char *sane(char *str)
return str; return str;
} }
/* vfork() disables some optimizations. Moving its use
* to minimal, non-inlined function saves bytes */
static NOINLINE void vfork_close_stdio_and_exec(char **argv)
{
if (vfork() == 0) {
// CHILD
// we are the helper. we wanna be silent.
// this call reopens stdio fds to "/dev/null"
// (no daemonization is done)
bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL);
BB_EXECVP(*argv, argv);
_exit(127);
}
}
static void exec_helper(const char *fname, char **argv) static void exec_helper(const char *fname, char **argv)
{ {
char *p, *q, *file; char *p, *q, *file;
@ -103,26 +116,24 @@ static void exec_helper(const char *fname, char **argv)
// next line, plz! // next line, plz!
q = p; q = p;
} }
free(file);
if (vfork() == 0) { vfork_close_stdio_and_exec(argv);
// CHILD
// we are the helper. we wanna be silent
// this call reopens stdio fds to "/dev/null"
// (no daemonization is done)
bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL);
BB_EXECVP(*argv, argv);
_exit(127);
}
// PARENT (or vfork error) // PARENT (or vfork error)
// clean up... // clean up...
free(file);
while (--env_idx >= 0) { while (--env_idx >= 0) {
*strchrnul(our_env[env_idx], '=') = '\0'; *strchrnul(our_env[env_idx], '=') = '\0';
unsetenv(our_env[env_idx]); unsetenv(our_env[env_idx]);
} }
} }
static char *xmalloc_read_stdin(void)
{
size_t max = 4 * 1024; /* more than enough for commands! */
return xmalloc_reads(STDIN_FILENO, NULL, &max);
}
int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE;
int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[])
{ {
@ -130,7 +141,7 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[])
char *s, *queue; char *s, *queue;
// read command // read command
s = xmalloc_reads(STDIN_FILENO, NULL); s = xmalloc_read_stdin();
// we understand only "receive job" command // we understand only "receive job" command
if (2 != *s) { if (2 != *s) {
@ -168,7 +179,7 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[])
write(STDOUT_FILENO, "", 1); write(STDOUT_FILENO, "", 1);
// get subcommand // get subcommand
s = xmalloc_reads(STDIN_FILENO, NULL); s = xmalloc_read_stdin();
if (!s) if (!s)
return EXIT_SUCCESS; // probably EOF return EXIT_SUCCESS; // probably EOF
// we understand only "control file" or "data file" cmds // we understand only "control file" or "data file" cmds

View File

@ -1061,7 +1061,7 @@ static int builtin_read(char **argv)
char *string; char *string;
const char *name = argv[1] ? argv[1] : "REPLY"; const char *name = argv[1] ? argv[1] : "REPLY";
string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name)); string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL);
return set_local_var(string, 0); return set_local_var(string, 0);
} }