diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-24 00:04:42 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-24 00:04:42 +0000 |
commit | 0b6c6a9c9f555a33d681290cce77510460457c03 (patch) | |
tree | 0d5f95c0cc0a2f6945aa97fa50266e8b8288da75 | |
parent | a79428998d76c1758ca12546e5db945a0cd64518 (diff) | |
download | busybox-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.h | 2 | ||||
-rw-r--r-- | libbb/read.c | 9 | ||||
-rw-r--r-- | printutils/lpd.c | 39 | ||||
-rw-r--r-- | shell/hush.c | 2 |
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). |
532 | extern char *xmalloc_reads(int fd, char *pfx); | 532 | extern char *xmalloc_reads(int fd, char *pfx, size_t *maxsz_p); |
533 | extern ssize_t read_close(int fd, void *buf, size_t count); | 533 | extern ssize_t read_close(int fd, void *buf, size_t count); |
534 | extern ssize_t open_read_close(const char *filename, void *buf, size_t count); | 534 | extern ssize_t open_read_close(const char *filename, void *buf, size_t count); |
535 | extern void *xmalloc_open_read_close(const char *filename, size_t *sizep); | 535 | extern 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). |
155 | char *xmalloc_reads(int fd, char *buf) | 155 | char *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 |
64 | static char *sane(char *str) | 62 | static 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 */ | ||
78 | static 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 | |||
78 | static void exec_helper(const char *fname, char **argv) | 91 | static 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 | ||
131 | static 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 | |||
126 | int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; | 137 | int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; |
127 | int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | 138 | int 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 | ||