aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-24 00:04:42 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-24 00:04:42 +0000
commit0b6c6a9c9f555a33d681290cce77510460457c03 (patch)
tree0d5f95c0cc0a2f6945aa97fa50266e8b8288da75
parenta79428998d76c1758ca12546e5db945a0cd64518 (diff)
downloadbusybox-w32-0b6c6a9c9f555a33d681290cce77510460457c03.tar.gz
busybox-w32-0b6c6a9c9f555a33d681290cce77510460457c03.tar.bz2
busybox-w32-0b6c6a9c9f555a33d681290cce77510460457c03.zip
lpd: fix OOM vulnerability (was eating arbitrarily large commands)
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/read.c9
-rw-r--r--printutils/lpd.c39
-rw-r--r--shell/hush.c2
4 files changed, 33 insertions, 19 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 9f208b390..07f74e476 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -529,7 +529,7 @@ extern char *reads(int fd, char *buf, size_t count);
529// Read one line a-la fgets. Reads byte-by-byte. 529// Read one line a-la fgets. Reads byte-by-byte.
530// Useful when it is important to not read ahead. 530// Useful when it is important to not read ahead.
531// Bytes are appended to pfx (which must be malloced, or NULL). 531// Bytes are appended to pfx (which must be malloced, or NULL).
532extern char *xmalloc_reads(int fd, char *pfx); 532extern char *xmalloc_reads(int fd, char *pfx, size_t *maxsz_p);
533extern ssize_t read_close(int fd, void *buf, size_t count); 533extern ssize_t read_close(int fd, void *buf, size_t count);
534extern ssize_t open_read_close(const char *filename, void *buf, size_t count); 534extern ssize_t open_read_close(const char *filename, void *buf, size_t count);
535extern void *xmalloc_open_read_close(const char *filename, size_t *sizep); 535extern void *xmalloc_open_read_close(const char *filename, size_t *sizep);
diff --git a/libbb/read.c b/libbb/read.c
index 575446536..9c025e3a3 100644
--- a/libbb/read.c
+++ b/libbb/read.c
@@ -152,13 +152,14 @@ char *reads(int fd, char *buffer, size_t size)
152// Read one line a-la fgets. Reads byte-by-byte. 152// Read one line a-la fgets. Reads byte-by-byte.
153// Useful when it is important to not read ahead. 153// Useful when it is important to not read ahead.
154// Bytes are appended to pfx (which must be malloced, or NULL). 154// Bytes are appended to pfx (which must be malloced, or NULL).
155char *xmalloc_reads(int fd, char *buf) 155char *xmalloc_reads(int fd, char *buf, size_t *maxsz_p)
156{ 156{
157 char *p; 157 char *p;
158 int sz = buf ? strlen(buf) : 0; 158 size_t sz = buf ? strlen(buf) : 0;
159 size_t maxsz = maxsz_p ? *maxsz_p : MAXINT(size_t);
159 160
160 goto jump_in; 161 goto jump_in;
161 while (1) { 162 while (sz < maxsz) {
162 if (p - buf == sz) { 163 if (p - buf == sz) {
163 jump_in: 164 jump_in:
164 buf = xrealloc(buf, sz + 128); 165 buf = xrealloc(buf, sz + 128);
@@ -178,6 +179,8 @@ char *xmalloc_reads(int fd, char *buf)
178 p++; 179 p++;
179 } 180 }
180 *p++ = '\0'; 181 *p++ = '\0';
182 if (maxsz_p)
183 *maxsz_p = p - buf - 1;
181 return xrealloc(buf, p - buf); 184 return xrealloc(buf, p - buf);
182} 185}
183 186
diff --git a/printutils/lpd.c b/printutils/lpd.c
index 45ad6d7e5..fe895939a 100644
--- a/printutils/lpd.c
+++ b/printutils/lpd.c
@@ -58,8 +58,6 @@
58 */ 58 */
59#include "libbb.h" 59#include "libbb.h"
60 60
61// TODO: xmalloc_reads is vulnerable to remote OOM attack!
62
63// strip argument of bad chars 61// strip argument of bad chars
64static char *sane(char *str) 62static char *sane(char *str)
65{ 63{
@@ -75,6 +73,21 @@ static char *sane(char *str)
75 return str; 73 return str;
76} 74}
77 75
76/* vfork() disables some optimizations. Moving its use
77 * to minimal, non-inlined function saves bytes */
78static NOINLINE void vfork_close_stdio_and_exec(char **argv)
79{
80 if (vfork() == 0) {
81 // CHILD
82 // we are the helper. we wanna be silent.
83 // this call reopens stdio fds to "/dev/null"
84 // (no daemonization is done)
85 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL);
86 BB_EXECVP(*argv, argv);
87 _exit(127);
88 }
89}
90
78static void exec_helper(const char *fname, char **argv) 91static void exec_helper(const char *fname, char **argv)
79{ 92{
80 char *p, *q, *file; 93 char *p, *q, *file;
@@ -103,26 +116,24 @@ static void exec_helper(const char *fname, char **argv)
103 // next line, plz! 116 // next line, plz!
104 q = p; 117 q = p;
105 } 118 }
119 free(file);
106 120
107 if (vfork() == 0) { 121 vfork_close_stdio_and_exec(argv);
108 // CHILD
109 // we are the helper. we wanna be silent
110 // this call reopens stdio fds to "/dev/null"
111 // (no daemonization is done)
112 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL);
113 BB_EXECVP(*argv, argv);
114 _exit(127);
115 }
116 122
117 // PARENT (or vfork error) 123 // PARENT (or vfork error)
118 // clean up... 124 // clean up...
119 free(file);
120 while (--env_idx >= 0) { 125 while (--env_idx >= 0) {
121 *strchrnul(our_env[env_idx], '=') = '\0'; 126 *strchrnul(our_env[env_idx], '=') = '\0';
122 unsetenv(our_env[env_idx]); 127 unsetenv(our_env[env_idx]);
123 } 128 }
124} 129}
125 130
131static char *xmalloc_read_stdin(void)
132{
133 size_t max = 4 * 1024; /* more than enough for commands! */
134 return xmalloc_reads(STDIN_FILENO, NULL, &max);
135}
136
126int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; 137int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE;
127int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) 138int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[])
128{ 139{
@@ -130,7 +141,7 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[])
130 char *s, *queue; 141 char *s, *queue;
131 142
132 // read command 143 // read command
133 s = xmalloc_reads(STDIN_FILENO, NULL); 144 s = xmalloc_read_stdin();
134 145
135 // we understand only "receive job" command 146 // we understand only "receive job" command
136 if (2 != *s) { 147 if (2 != *s) {
@@ -168,7 +179,7 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[])
168 write(STDOUT_FILENO, "", 1); 179 write(STDOUT_FILENO, "", 1);
169 180
170 // get subcommand 181 // get subcommand
171 s = xmalloc_reads(STDIN_FILENO, NULL); 182 s = xmalloc_read_stdin();
172 if (!s) 183 if (!s)
173 return EXIT_SUCCESS; // probably EOF 184 return EXIT_SUCCESS; // probably EOF
174 // we understand only "control file" or "data file" cmds 185 // we understand only "control file" or "data file" cmds
diff --git a/shell/hush.c b/shell/hush.c
index eb0633b18..545367cb6 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1061,7 +1061,7 @@ static int builtin_read(char **argv)
1061 char *string; 1061 char *string;
1062 const char *name = argv[1] ? argv[1] : "REPLY"; 1062 const char *name = argv[1] ? argv[1] : "REPLY";
1063 1063
1064 string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name)); 1064 string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL);
1065 return set_local_var(string, 0); 1065 return set_local_var(string, 0);
1066} 1066}
1067 1067