diff options
author | Ron Yorston <rmy@pobox.com> | 2025-05-19 08:34:32 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2025-05-19 08:34:32 +0100 |
commit | 64bf69893bd99c305d13a956389f216e7d15c682 (patch) | |
tree | 7fa7d449f0633c86c1248c0bb86363dd9f46da38 | |
parent | a807cdfa95cf4af2f84e207ed15887cc3514cb43 (diff) | |
parent | 5f07327251c93184dfcfc8d978fc35705930ec53 (diff) | |
download | busybox-w32-merge.tar.gz busybox-w32-merge.tar.bz2 busybox-w32-merge.zip |
Merge branch 'busybox' into mergemerge
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | archival/Config.src | 11 | ||||
-rw-r--r-- | archival/bbunzip.c | 6 | ||||
-rw-r--r-- | archival/cpio.c | 6 | ||||
-rw-r--r-- | archival/libarchive/data_extract_all.c | 8 | ||||
-rw-r--r-- | archival/libarchive/open_transformer.c | 26 | ||||
-rw-r--r-- | archival/libarchive/unsafe_prefix.c | 6 | ||||
-rw-r--r-- | archival/rpm.c | 9 | ||||
-rw-r--r-- | archival/tar.c | 2 | ||||
-rw-r--r-- | include/libbb.h | 6 | ||||
-rw-r--r-- | init/init.c | 18 | ||||
-rw-r--r-- | miscutils/fbsplash.c | 2 | ||||
-rw-r--r-- | miscutils/man.c | 2 | ||||
-rw-r--r-- | networking/udhcp/d6_dhcpc.c | 193 | ||||
-rw-r--r-- | networking/udhcp/d6_packet.c | 16 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 58 | ||||
-rw-r--r-- | runit/chpst.c | 3 | ||||
-rwxr-xr-x | scripts/kconfig/lxdialog/check-lxdialog.sh | 2 | ||||
-rw-r--r-- | sysklogd/syslogd.c | 2 | ||||
-rwxr-xr-x | testsuite/cpio.tests | 23 |
20 files changed, 286 insertions, 119 deletions
@@ -688,8 +688,12 @@ quiet_cmd_busybox__ ?= LINK $@ | |||
688 | "$(core-y)" \ | 688 | "$(core-y)" \ |
689 | "$(libs-y)" \ | 689 | "$(libs-y)" \ |
690 | "$(LDLIBS)" \ | 690 | "$(LDLIBS)" \ |
691 | "$(CONFIG_EXTRA_LDLIBS)" \ | 691 | $(CONFIG_EXTRA_LDLIBS) \ |
692 | && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h | 692 | && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h |
693 | # ^^^ note: CONFIG_xyz strings already have double quotes: their value | ||
694 | # is '"LIB LIB2"', therefore $(CONFIG_EXTRA_LDLIBS) above must NOT be written | ||
695 | # as "$(CONFIG_EXTRA_LDLIBS)", it would be passed as ""LIB LIB2"", | ||
696 | # and LIB2 would end up in $9, not $8 (and lost or misinterpreted). | ||
693 | 697 | ||
694 | # Generate System.map | 698 | # Generate System.map |
695 | quiet_cmd_sysmap = SYSMAP | 699 | quiet_cmd_sysmap = SYSMAP |
diff --git a/archival/Config.src b/archival/Config.src index 6f4f30c43..cbcd7217c 100644 --- a/archival/Config.src +++ b/archival/Config.src | |||
@@ -35,4 +35,15 @@ config FEATURE_LZMA_FAST | |||
35 | This option reduces decompression time by about 25% at the cost of | 35 | This option reduces decompression time by about 25% at the cost of |
36 | a 1K bigger binary. | 36 | a 1K bigger binary. |
37 | 37 | ||
38 | config FEATURE_PATH_TRAVERSAL_PROTECTION | ||
39 | bool "Prevent extraction of filenames with /../ path component" | ||
40 | default n | ||
41 | help | ||
42 | busybox tar and unzip remove "PREFIX/../" (if it exists) | ||
43 | from extracted names. | ||
44 | This option enables this behavior for all other unpacking applets, | ||
45 | such as cpio, ar, rpm. | ||
46 | GNU cpio 2.15 has NO such sanity check. | ||
47 | # try other archivers and document their behavior? | ||
48 | |||
38 | endmenu | 49 | endmenu |
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index fb5deb0ce..1f1f28b61 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -71,8 +71,8 @@ int FAST_FUNC bbunpack(char **argv, | |||
71 | goto err; | 71 | goto err; |
72 | } else { | 72 | } else { |
73 | /* "clever zcat" with FILE */ | 73 | /* "clever zcat" with FILE */ |
74 | /* fail_if_not_compressed because zcat refuses uncompressed input */ | 74 | /* die_if_not_compressed because zcat refuses uncompressed input */ |
75 | int fd = open_zipped(filename, /*fail_if_not_compressed:*/ 1); | 75 | int fd = open_zipped(filename, /*die_if_not_compressed:*/ 1); |
76 | if (fd < 0) | 76 | if (fd < 0) |
77 | goto err_name; | 77 | goto err_name; |
78 | xmove_fd(fd, STDIN_FILENO); | 78 | xmove_fd(fd, STDIN_FILENO); |
@@ -80,7 +80,7 @@ int FAST_FUNC bbunpack(char **argv, | |||
80 | } else | 80 | } else |
81 | if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) { | 81 | if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) { |
82 | /* "clever zcat" on stdin */ | 82 | /* "clever zcat" on stdin */ |
83 | if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1)) | 83 | if (setup_unzip_on_fd(STDIN_FILENO, /*die_if_not_compressed*/ 1)) |
84 | goto err; | 84 | goto err; |
85 | } | 85 | } |
86 | 86 | ||
diff --git a/archival/cpio.c b/archival/cpio.c index 167931bdb..933d520c2 100644 --- a/archival/cpio.c +++ b/archival/cpio.c | |||
@@ -354,6 +354,12 @@ static NOINLINE int cpio_o(void) | |||
354 | #endif | 354 | #endif |
355 | #endif | 355 | #endif |
356 | 356 | ||
357 | if (sizeof(st.st_size) > 4 | ||
358 | && st.st_size > (off_t)0xffffffff | ||
359 | ) { | ||
360 | bb_error_msg_and_die("error: file '%s' is larger than 4GB", name); | ||
361 | } | ||
362 | |||
357 | bytes += printf("070701" | 363 | bytes += printf("070701" |
358 | "%08X%08X%08X%08X%08X%08X%08X" | 364 | "%08X%08X%08X%08X%08X%08X%08X" |
359 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ | 365 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ |
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index 049c2c156..8a69711c1 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c | |||
@@ -65,6 +65,14 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
65 | } while (--n != 0); | 65 | } while (--n != 0); |
66 | } | 66 | } |
67 | #endif | 67 | #endif |
68 | #if ENABLE_FEATURE_PATH_TRAVERSAL_PROTECTION | ||
69 | /* Strip leading "/" and up to last "/../" path component */ | ||
70 | dst_name = (char *)strip_unsafe_prefix(dst_name); | ||
71 | #endif | ||
72 | // ^^^ This may be a problem if some applets do need to extract absolute names. | ||
73 | // (Probably will need to invent ARCHIVE_ALLOW_UNSAFE_NAME flag). | ||
74 | // You might think that rpm needs it, but in my tests rpm's internal cpio | ||
75 | // archive has names like "./usr/bin/FOO", not "/usr/bin/FOO". | ||
68 | 76 | ||
69 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { | 77 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { |
70 | char *slash = strrchr(dst_name, '/'); | 78 | char *slash = strrchr(dst_name, '/'); |
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 3d202ad26..a949c4509 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c | |||
@@ -164,7 +164,7 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog) | |||
164 | /* Used by e.g. rpm which gives us a fd without filename, | 164 | /* Used by e.g. rpm which gives us a fd without filename, |
165 | * thus we can't guess the format from filename's extension. | 165 | * thus we can't guess the format from filename's extension. |
166 | */ | 166 | */ |
167 | static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) | 167 | static transformer_state_t *setup_transformer_on_fd(int fd, int die_if_not_compressed) |
168 | { | 168 | { |
169 | transformer_state_t *xstate; | 169 | transformer_state_t *xstate; |
170 | 170 | ||
@@ -211,7 +211,7 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp | |||
211 | } | 211 | } |
212 | 212 | ||
213 | /* No known magic seen */ | 213 | /* No known magic seen */ |
214 | if (fail_if_not_compressed) | 214 | if (die_if_not_compressed) |
215 | bb_simple_error_msg_and_die("no gzip" | 215 | bb_simple_error_msg_and_die("no gzip" |
216 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") | 216 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") |
217 | IF_FEATURE_SEAMLESS_XZ("/xz") | 217 | IF_FEATURE_SEAMLESS_XZ("/xz") |
@@ -247,13 +247,15 @@ static void fork_transformer_and_free(transformer_state_t *xstate) | |||
247 | /* Used by e.g. rpm which gives us a fd without filename, | 247 | /* Used by e.g. rpm which gives us a fd without filename, |
248 | * thus we can't guess the format from filename's extension. | 248 | * thus we can't guess the format from filename's extension. |
249 | */ | 249 | */ |
250 | int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) | 250 | int FAST_FUNC setup_unzip_on_fd(int fd, int die_if_not_compressed) |
251 | { | 251 | { |
252 | transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | 252 | transformer_state_t *xstate = setup_transformer_on_fd(fd, die_if_not_compressed); |
253 | 253 | ||
254 | if (!xstate->xformer) { | 254 | if (!xstate->xformer) { |
255 | /* Not compressed */ | ||
256 | int retval = xstate->signature_skipped; /* never zero */ | ||
255 | free(xstate); | 257 | free(xstate); |
256 | return 1; | 258 | return retval; |
257 | } | 259 | } |
258 | 260 | ||
259 | fork_transformer_and_free(xstate); | 261 | fork_transformer_and_free(xstate); |
@@ -271,7 +273,7 @@ void FAST_FUNC setup_lzma_on_fd(int fd) | |||
271 | } | 273 | } |
272 | #endif | 274 | #endif |
273 | 275 | ||
274 | static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) | 276 | static transformer_state_t *open_transformer(const char *fname, int die_if_not_compressed) |
275 | { | 277 | { |
276 | transformer_state_t *xstate; | 278 | transformer_state_t *xstate; |
277 | int fd; | 279 | int fd; |
@@ -291,18 +293,18 @@ static transformer_state_t *open_transformer(const char *fname, int fail_if_not_ | |||
291 | } | 293 | } |
292 | } | 294 | } |
293 | 295 | ||
294 | xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | 296 | xstate = setup_transformer_on_fd(fd, die_if_not_compressed); |
295 | 297 | ||
296 | return xstate; | 298 | return xstate; |
297 | } | 299 | } |
298 | 300 | ||
299 | int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) | 301 | int FAST_FUNC open_zipped(const char *fname, int die_if_not_compressed) |
300 | { | 302 | { |
301 | int fd; | 303 | int fd; |
302 | transformer_state_t *xstate; | 304 | transformer_state_t *xstate; |
303 | 305 | ||
304 | xstate = open_transformer(fname, fail_if_not_compressed); | 306 | xstate = open_transformer(fname, die_if_not_compressed); |
305 | if (!xstate) | 307 | if (!xstate) /* open error */ |
306 | return -1; | 308 | return -1; |
307 | 309 | ||
308 | fd = xstate->src_fd; | 310 | fd = xstate->src_fd; |
@@ -333,7 +335,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ | |||
333 | transformer_state_t *xstate; | 335 | transformer_state_t *xstate; |
334 | char *image; | 336 | char *image; |
335 | 337 | ||
336 | xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0); | 338 | xstate = open_transformer(fname, /*die_if_not_compressed:*/ 0); |
337 | if (!xstate) /* file open error */ | 339 | if (!xstate) /* file open error */ |
338 | return NULL; | 340 | return NULL; |
339 | 341 | ||
@@ -378,7 +380,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ | |||
378 | int fd; | 380 | int fd; |
379 | char *image; | 381 | char *image; |
380 | 382 | ||
381 | fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0); | 383 | fd = open_zipped(fname, /*die_if_not_compressed:*/ 0); |
382 | if (fd < 0) | 384 | if (fd < 0) |
383 | return NULL; | 385 | return NULL; |
384 | 386 | ||
diff --git a/archival/libarchive/unsafe_prefix.c b/archival/libarchive/unsafe_prefix.c index 33e487bf9..667081195 100644 --- a/archival/libarchive/unsafe_prefix.c +++ b/archival/libarchive/unsafe_prefix.c | |||
@@ -14,7 +14,11 @@ const char* FAST_FUNC strip_unsafe_prefix(const char *str) | |||
14 | cp++; | 14 | cp++; |
15 | continue; | 15 | continue; |
16 | } | 16 | } |
17 | if (is_prefixed_with(cp, "/../"+1)) { | 17 | /* We are called lots of times. |
18 | * is_prefixed_with(cp, "../") is slower than open-coding it, | ||
19 | * with minimal code growth (~few bytes). | ||
20 | */ | ||
21 | if (cp[0] == '.' && cp[1] == '.' && cp[2] == '/') { | ||
18 | cp += 3; | 22 | cp += 3; |
19 | continue; | 23 | continue; |
20 | } | 24 | } |
diff --git a/archival/rpm.c b/archival/rpm.c index d83c33137..c2f0550ff 100644 --- a/archival/rpm.c +++ b/archival/rpm.c | |||
@@ -330,7 +330,7 @@ static void extract_cpio(int fd, const char *source_rpm) | |||
330 | archive_handle->src_fd = fd; | 330 | archive_handle->src_fd = fd; |
331 | /*archive_handle->offset = 0; - init_handle() did it */ | 331 | /*archive_handle->offset = 0; - init_handle() did it */ |
332 | 332 | ||
333 | setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); | 333 | setup_unzip_on_fd(archive_handle->src_fd, /*die_if_not_compressed:*/ 1); |
334 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) | 334 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) |
335 | continue; | 335 | continue; |
336 | } | 336 | } |
@@ -549,6 +549,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
549 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ | 549 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ |
550 | // signal(SIGCHLD, check_errors_in_children); | 550 | // signal(SIGCHLD, check_errors_in_children); |
551 | 551 | ||
552 | str = NULL; | ||
552 | if (ENABLE_FEATURE_SEAMLESS_LZMA | 553 | if (ENABLE_FEATURE_SEAMLESS_LZMA |
553 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL | 554 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL |
554 | && strcmp(str, "lzma") == 0 | 555 | && strcmp(str, "lzma") == 0 |
@@ -557,7 +558,11 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
557 | // set up decompressor without detection | 558 | // set up decompressor without detection |
558 | setup_lzma_on_fd(rpm_fd); | 559 | setup_lzma_on_fd(rpm_fd); |
559 | } else { | 560 | } else { |
560 | setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); | 561 | int signature_bytes = setup_unzip_on_fd(rpm_fd, /*die_if_not_compressed:*/ 0); |
562 | if (signature_bytes != 0) { | ||
563 | xlseek(rpm_fd, - signature_bytes, SEEK_CUR); | ||
564 | bb_error_msg("warning, unknown compression '%s'", str); | ||
565 | } | ||
561 | } | 566 | } |
562 | 567 | ||
563 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) | 568 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) |
diff --git a/archival/tar.c b/archival/tar.c index 23ea02b5d..fd20d6ce7 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -1188,7 +1188,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1188 | * on e.g. tarball with 1st file named "BZh5". | 1188 | * on e.g. tarball with 1st file named "BZh5". |
1189 | */ | 1189 | */ |
1190 | ) { | 1190 | ) { |
1191 | tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); | 1191 | tar_handle->src_fd = open_zipped(tar_filename, /*die_if_not_compressed:*/ 0); |
1192 | if (tar_handle->src_fd < 0) | 1192 | if (tar_handle->src_fd < 0) |
1193 | bb_perror_msg_and_die("can't open '%s'", tar_filename); | 1193 | bb_perror_msg_and_die("can't open '%s'", tar_filename); |
1194 | } else { | 1194 | } else { |
diff --git a/include/libbb.h b/include/libbb.h index bc1453e12..7357d2907 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1071,13 +1071,13 @@ unsigned bb_clk_tck(void) FAST_FUNC; | |||
1071 | 1071 | ||
1072 | #if SEAMLESS_COMPRESSION | 1072 | #if SEAMLESS_COMPRESSION |
1073 | /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ | 1073 | /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ |
1074 | int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; | 1074 | int setup_unzip_on_fd(int fd, int die_if_not_compressed) FAST_FUNC; |
1075 | /* Autodetects .gz etc */ | 1075 | /* Autodetects .gz etc */ |
1076 | extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; | 1076 | extern int open_zipped(const char *fname, int die_if_not_compressed) FAST_FUNC; |
1077 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; | 1077 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; |
1078 | #else | 1078 | #else |
1079 | # define setup_unzip_on_fd(...) (0) | 1079 | # define setup_unzip_on_fd(...) (0) |
1080 | # define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); | 1080 | # define open_zipped(fname, die_if_not_compressed) open((fname), O_RDONLY); |
1081 | # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) | 1081 | # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) |
1082 | #endif | 1082 | #endif |
1083 | /* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ | 1083 | /* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ |
diff --git a/init/init.c b/init/init.c index 2ee1e4cde..797e0a0eb 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -1198,17 +1198,29 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1198 | /* Wait for any child process(es) to exit */ | 1198 | /* Wait for any child process(es) to exit */ |
1199 | while (1) { | 1199 | while (1) { |
1200 | pid_t wpid; | 1200 | pid_t wpid; |
1201 | int status; | ||
1201 | struct init_action *a; | 1202 | struct init_action *a; |
1202 | 1203 | ||
1203 | wpid = waitpid(-1, NULL, WNOHANG); | 1204 | wpid = waitpid(-1, &status, WNOHANG); |
1204 | if (wpid <= 0) | 1205 | if (wpid <= 0) |
1205 | break; | 1206 | break; |
1206 | 1207 | ||
1207 | a = mark_terminated(wpid); | 1208 | a = mark_terminated(wpid); |
1208 | if (a) { | 1209 | if (a) { |
1209 | message(L_LOG, "process '%s' (pid %u) exited. " | 1210 | const char *s = "killed, signal"; |
1211 | int ex = WTERMSIG(status); | ||
1212 | /* "if (!WIFSIGNALED(status))" generates more code: | ||
1213 | * on linux, WIFEXITED(status) is "WTERMSIG(status) == 0" | ||
1214 | * and WTERMSIG(status) is known, so compiler optimizes. | ||
1215 | */ | ||
1216 | if (WIFEXITED(status)) { | ||
1217 | s = "exited, exitcode"; | ||
1218 | ex = WEXITSTATUS(status); | ||
1219 | } | ||
1220 | message(L_LOG, "process '%s' (pid %u) %s:%d. " | ||
1210 | "Scheduling for restart.", | 1221 | "Scheduling for restart.", |
1211 | a->command, (unsigned)wpid); | 1222 | a->command, (unsigned)wpid, |
1223 | s, ex); | ||
1212 | } | 1224 | } |
1213 | } | 1225 | } |
1214 | 1226 | ||
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c index 2934d8eb7..912a501a3 100644 --- a/miscutils/fbsplash.c +++ b/miscutils/fbsplash.c | |||
@@ -382,7 +382,7 @@ static void fb_drawimage(void) | |||
382 | if (LONE_DASH(G.image_filename)) { | 382 | if (LONE_DASH(G.image_filename)) { |
383 | theme_file = stdin; | 383 | theme_file = stdin; |
384 | } else { | 384 | } else { |
385 | int fd = open_zipped(G.image_filename, /*fail_if_not_compressed:*/ 0); | 385 | int fd = open_zipped(G.image_filename, /*die_if_not_compressed:*/ 0); |
386 | if (fd < 0) | 386 | if (fd < 0) |
387 | bb_simple_perror_msg_and_die(G.image_filename); | 387 | bb_simple_perror_msg_and_die(G.image_filename); |
388 | theme_file = xfdopen_for_read(fd); | 388 | theme_file = xfdopen_for_read(fd); |
diff --git a/miscutils/man.c b/miscutils/man.c index 3954455b4..38c1b9aa3 100644 --- a/miscutils/man.c +++ b/miscutils/man.c | |||
@@ -143,7 +143,7 @@ static int run_pipe(char *man_filename, int man, int level) | |||
143 | 143 | ||
144 | ordinary_manpage: | 144 | ordinary_manpage: |
145 | close(STDIN_FILENO); | 145 | close(STDIN_FILENO); |
146 | open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ | 146 | open_zipped(man_filename, /*die_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ |
147 | if (man) { | 147 | if (man) { |
148 | int w = get_terminal_width(-1); | 148 | int w = get_terminal_width(-1); |
149 | if (w > 10) | 149 | if (w > 10) |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 79cef1999..19c961d5c 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -148,10 +148,11 @@ enum { | |||
148 | OPT_o = 1 << 12, | 148 | OPT_o = 1 << 12, |
149 | OPT_x = 1 << 13, | 149 | OPT_x = 1 << 13, |
150 | OPT_f = 1 << 14, | 150 | OPT_f = 1 << 14, |
151 | OPT_l = 1 << 15, | 151 | OPT_m = 1 << 15, |
152 | OPT_d = 1 << 16, | 152 | OPT_l = 1 << 16, |
153 | OPT_d = 1 << 17, | ||
153 | /* The rest has variable bit positions, need to be clever */ | 154 | /* The rest has variable bit positions, need to be clever */ |
154 | OPTBIT_d = 16, | 155 | OPTBIT_d = 17, |
155 | USE_FOR_MMU( OPTBIT_b,) | 156 | USE_FOR_MMU( OPTBIT_b,) |
156 | ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | 157 | ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) |
157 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | 158 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) |
@@ -268,6 +269,23 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end) | |||
268 | //case D6_OPT_SERVERID: | 269 | //case D6_OPT_SERVERID: |
269 | case D6_OPT_IA_NA: | 270 | case D6_OPT_IA_NA: |
270 | case D6_OPT_IA_PD: | 271 | case D6_OPT_IA_PD: |
272 | /* 0 1 2 3 | ||
273 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
274 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
275 | * | OPTION_IA_PD | option-length | | ||
276 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
277 | * | IAID (4 octets) | | ||
278 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
279 | * | T1 | | ||
280 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
281 | * | T2 | | ||
282 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
283 | * . . | ||
284 | * . IA_PD-options . | ||
285 | * . . | ||
286 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
287 | */ | ||
288 | /* recurse to handle "IA_PD-options" field */ | ||
271 | option_to_env(option + 16, option + 4 + option[3]); | 289 | option_to_env(option + 16, option + 4 + option[3]); |
272 | break; | 290 | break; |
273 | //case D6_OPT_IA_TA: | 291 | //case D6_OPT_IA_TA: |
@@ -604,6 +622,31 @@ static NOINLINE int send_d6_info_request(void) | |||
604 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); | 622 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); |
605 | } | 623 | } |
606 | 624 | ||
625 | /* | ||
626 | * RFC 3315 10. Identity Association | ||
627 | * | ||
628 | * An "identity-association" (IA) is a construct through which a server | ||
629 | * and a client can identify, group, and manage a set of related IPv6 | ||
630 | * addresses. Each IA consists of an IAID and associated configuration | ||
631 | * information. | ||
632 | * | ||
633 | * A client must associate at least one distinct IA with each of its | ||
634 | * network interfaces for which it is to request the assignment of IPv6 | ||
635 | * addresses from a DHCP server. The client uses the IAs assigned to an | ||
636 | * interface to obtain configuration information from a server for that | ||
637 | * interface. Each IA must be associated with exactly one interface. | ||
638 | * | ||
639 | * The IAID uniquely identifies the IA and must be chosen to be unique | ||
640 | * among the IAIDs on the client. The IAID is chosen by the client. | ||
641 | * For any given use of an IA by the client, the IAID for that IA MUST | ||
642 | * be consistent across restarts of the DHCP client... | ||
643 | */ | ||
644 | /* Generate IAID. We base it on our MAC address' last 4 bytes */ | ||
645 | static void generate_iaid(uint8_t *iaid) | ||
646 | { | ||
647 | memcpy(iaid, &client_data.client_mac[2], 4); | ||
648 | } | ||
649 | |||
607 | /* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. | 650 | /* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. |
608 | * | 651 | * |
609 | * RFC 3315 17.1.1. Creation of Solicit Messages | 652 | * RFC 3315 17.1.1. Creation of Solicit Messages |
@@ -703,7 +746,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6) | |||
703 | client6_data.ia_na = xzalloc(len); | 746 | client6_data.ia_na = xzalloc(len); |
704 | client6_data.ia_na->code = D6_OPT_IA_NA; | 747 | client6_data.ia_na->code = D6_OPT_IA_NA; |
705 | client6_data.ia_na->len = len - 4; | 748 | client6_data.ia_na->len = len - 4; |
706 | *(bb__aliased_uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ | 749 | generate_iaid(client6_data.ia_na->data); /* IAID */ |
707 | if (requested_ipv6) { | 750 | if (requested_ipv6) { |
708 | struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); | 751 | struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); |
709 | iaaddr->code = D6_OPT_IAADDR; | 752 | iaaddr->code = D6_OPT_IAADDR; |
@@ -721,7 +764,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6) | |||
721 | client6_data.ia_pd = xzalloc(len); | 764 | client6_data.ia_pd = xzalloc(len); |
722 | client6_data.ia_pd->code = D6_OPT_IA_PD; | 765 | client6_data.ia_pd->code = D6_OPT_IA_PD; |
723 | client6_data.ia_pd->len = len - 4; | 766 | client6_data.ia_pd->len = len - 4; |
724 | *(bb__aliased_uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */ | 767 | generate_iaid(client6_data.ia_pd->data); /* IAID */ |
725 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); | 768 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); |
726 | } | 769 | } |
727 | 770 | ||
@@ -1131,12 +1174,11 @@ static void client_background(void) | |||
1131 | //usage:#endif | 1174 | //usage:#endif |
1132 | //usage:#define udhcpc6_trivial_usage | 1175 | //usage:#define udhcpc6_trivial_usage |
1133 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" | 1176 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" |
1134 | //usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-ldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." | 1177 | //usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-mldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." |
1135 | //usage:#define udhcpc6_full_usage "\n" | 1178 | //usage:#define udhcpc6_full_usage "\n" |
1136 | //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" | 1179 | //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" |
1137 | //usage: "\n -p FILE Create pidfile" | 1180 | //usage: "\n -p FILE Create pidfile" |
1138 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")" | 1181 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")" |
1139 | //usage: "\n -B Request broadcast replies" | ||
1140 | //usage: "\n -t N Send up to N discover packets" | 1182 | //usage: "\n -t N Send up to N discover packets" |
1141 | //usage: "\n -T SEC Pause between packets (default 3)" | 1183 | //usage: "\n -T SEC Pause between packets (default 3)" |
1142 | //usage: "\n -A SEC Wait if lease is not obtained (default 20)" | 1184 | //usage: "\n -A SEC Wait if lease is not obtained (default 20)" |
@@ -1154,6 +1196,7 @@ static void client_background(void) | |||
1154 | ////usage: IF_FEATURE_UDHCPC_ARPING( | 1196 | ////usage: IF_FEATURE_UDHCPC_ARPING( |
1155 | ////usage: "\n -a Use arping to validate offered address" | 1197 | ////usage: "\n -a Use arping to validate offered address" |
1156 | ////usage: ) | 1198 | ////usage: ) |
1199 | //usage: "\n -m Send multicast renew requests rather than unicast ones" | ||
1157 | //usage: "\n -l Send 'information request' instead of 'solicit'" | 1200 | //usage: "\n -l Send 'information request' instead of 'solicit'" |
1158 | //usage: "\n (used for servers which do not assign IPv6 addresses)" | 1201 | //usage: "\n (used for servers which do not assign IPv6 addresses)" |
1159 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" | 1202 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" |
@@ -1211,7 +1254,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1211 | /* Parse command line */ | 1254 | /* Parse command line */ |
1212 | opt = getopt32long(argv, "^" | 1255 | opt = getopt32long(argv, "^" |
1213 | /* O,x: list; -T,-t,-A take numeric param */ | 1256 | /* O,x: list; -T,-t,-A take numeric param */ |
1214 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld" | 1257 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*fmld" |
1215 | USE_FOR_MMU("b") | 1258 | USE_FOR_MMU("b") |
1216 | ///IF_FEATURE_UDHCPC_ARPING("a") | 1259 | ///IF_FEATURE_UDHCPC_ARPING("a") |
1217 | IF_FEATURE_UDHCP_PORT("P:") | 1260 | IF_FEATURE_UDHCP_PORT("P:") |
@@ -1464,7 +1507,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1464 | if (opt & OPT_l) | 1507 | if (opt & OPT_l) |
1465 | send_d6_info_request(); | 1508 | send_d6_info_request(); |
1466 | else | 1509 | else |
1467 | send_d6_renew(&srv6_buf, requested_ipv6); | 1510 | send_d6_renew(OPT_m ? NULL : &srv6_buf, requested_ipv6); |
1468 | timeout = discover_timeout; | 1511 | timeout = discover_timeout; |
1469 | packet_num++; | 1512 | packet_num++; |
1470 | continue; | 1513 | continue; |
@@ -1606,62 +1649,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1606 | case RENEW_REQUESTED: | 1649 | case RENEW_REQUESTED: |
1607 | case REBINDING: | 1650 | case REBINDING: |
1608 | if (packet.d6_msg_type == D6_MSG_REPLY) { | 1651 | if (packet.d6_msg_type == D6_MSG_REPLY) { |
1609 | unsigned start; | ||
1610 | uint32_t lease_seconds; | ||
1611 | struct d6_option *option; | ||
1612 | unsigned address_timeout; | ||
1613 | unsigned prefix_timeout; | ||
1614 | type_is_ok: | ||
1615 | change_listen_mode(LISTEN_NONE); | ||
1616 | |||
1617 | address_timeout = 0; | ||
1618 | prefix_timeout = 0; | ||
1619 | option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); | ||
1620 | if (option && (option->data[0] | option->data[1]) != 0) { | ||
1621 | ///FIXME: | ||
1622 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1623 | // | OPTION_STATUS_CODE | option-len | | ||
1624 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1625 | // | status-code | | | ||
1626 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ||
1627 | // . status-message . | ||
1628 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1629 | // so why do we think it's NAK if data[0] is zero but data[1] is not? That's wrong... | ||
1630 | // we should also check that option->len is ok (i.e. not 0), right? | ||
1631 | /* return to init state */ | ||
1632 | bb_info_msg("received DHCP NAK (%u)", option->data[4]); | ||
1633 | d6_run_script(packet.d6_options, | ||
1634 | packet_end, "nak"); | ||
1635 | if (client_data.state != REQUESTING) | ||
1636 | d6_run_script_no_option("deconfig"); | ||
1637 | sleep(3); /* avoid excessive network traffic */ | ||
1638 | client_data.state = INIT_SELECTING; | ||
1639 | client_data.first_secs = 0; /* make secs field count from 0 */ | ||
1640 | requested_ipv6 = NULL; | ||
1641 | timeout = 0; | ||
1642 | packet_num = 0; | ||
1643 | continue; | ||
1644 | } | ||
1645 | option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); | ||
1646 | if (!option) { | ||
1647 | bb_simple_info_msg("no server ID, ignoring packet"); | ||
1648 | continue; | ||
1649 | /* still selecting - this server looks bad */ | ||
1650 | } | ||
1651 | //Note: we do not bother comparing server IDs in Advertise and Reply msgs. | ||
1652 | //server_id variable is used solely for creation of proper server_id option | ||
1653 | //in outgoing packets. (why DHCPv6 even introduced it is a mystery). | ||
1654 | free(client6_data.server_id); | ||
1655 | client6_data.server_id = option; | ||
1656 | if (packet.d6_msg_type == D6_MSG_ADVERTISE) { | ||
1657 | /* enter requesting state */ | ||
1658 | change_listen_mode(LISTEN_RAW); | ||
1659 | client_data.state = REQUESTING; | ||
1660 | timeout = 0; | ||
1661 | packet_num = 0; | ||
1662 | continue; | ||
1663 | } | ||
1664 | /* It's a D6_MSG_REPLY */ | ||
1665 | /* | 1652 | /* |
1666 | * RFC 3315 18.1.8. Receipt of Reply Messages | 1653 | * RFC 3315 18.1.8. Receipt of Reply Messages |
1667 | * | 1654 | * |
@@ -1747,6 +1734,67 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1747 | * . . | 1734 | * . . |
1748 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 1735 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1749 | */ | 1736 | */ |
1737 | unsigned start; | ||
1738 | uint32_t lease_seconds; | ||
1739 | struct d6_option *option; | ||
1740 | unsigned address_timeout; | ||
1741 | unsigned prefix_timeout; | ||
1742 | type_is_ok: | ||
1743 | change_listen_mode(LISTEN_NONE); | ||
1744 | |||
1745 | address_timeout = 0; | ||
1746 | prefix_timeout = 0; | ||
1747 | option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); | ||
1748 | if (option) { | ||
1749 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1750 | // | OPTION_STATUS_CODE | option-len | | ||
1751 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1752 | // | status-code | | | ||
1753 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ||
1754 | // . status-message . | ||
1755 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1756 | unsigned len, status; | ||
1757 | len = ((unsigned)option->len_hi << 8) + option->len; | ||
1758 | if (len < 2) { | ||
1759 | bb_simple_error_msg("invalid OPTION_STATUS_CODE, ignoring packet"); | ||
1760 | continue; | ||
1761 | } | ||
1762 | status = ((unsigned)option->data[0] << 8) + option->data[1]; | ||
1763 | if (status != 0) { | ||
1764 | //TODO: handle status == 5 (UseMulticast)? | ||
1765 | /* return to init state */ | ||
1766 | bb_info_msg("received DHCP NAK: %u '%.*s'", status, len - 2, option->data + 2); | ||
1767 | d6_run_script(packet.d6_options, packet_end, "nak"); | ||
1768 | if (client_data.state != REQUESTING) | ||
1769 | d6_run_script_no_option("deconfig"); | ||
1770 | sleep(3); /* avoid excessive network traffic */ | ||
1771 | client_data.state = INIT_SELECTING; | ||
1772 | client_data.first_secs = 0; /* make secs field count from 0 */ | ||
1773 | requested_ipv6 = NULL; | ||
1774 | timeout = 0; | ||
1775 | packet_num = 0; | ||
1776 | continue; | ||
1777 | } | ||
1778 | } | ||
1779 | option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); | ||
1780 | if (!option) { | ||
1781 | bb_simple_info_msg("no server ID, ignoring packet"); | ||
1782 | continue; | ||
1783 | /* still selecting - this server looks bad */ | ||
1784 | } | ||
1785 | //Note: we do not bother comparing server IDs in Advertise and Reply msgs. | ||
1786 | //server_id variable is used solely for creation of proper server_id option | ||
1787 | //in outgoing packets. (why DHCPv6 even introduced it is a mystery). | ||
1788 | free(client6_data.server_id); | ||
1789 | client6_data.server_id = option; | ||
1790 | if (packet.d6_msg_type == D6_MSG_ADVERTISE) { | ||
1791 | /* enter requesting state */ | ||
1792 | change_listen_mode(LISTEN_RAW); | ||
1793 | client_data.state = REQUESTING; | ||
1794 | timeout = 0; | ||
1795 | packet_num = 0; | ||
1796 | continue; | ||
1797 | } | ||
1750 | if (option_mask32 & OPT_r) { | 1798 | if (option_mask32 & OPT_r) { |
1751 | struct d6_option *iaaddr; | 1799 | struct d6_option *iaaddr; |
1752 | 1800 | ||
@@ -1790,6 +1838,21 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1790 | 1838 | ||
1791 | free(client6_data.ia_pd); | 1839 | free(client6_data.ia_pd); |
1792 | client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); | 1840 | client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); |
1841 | // 0 1 2 3 | ||
1842 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
1843 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1844 | // | OPTION_IA_PD | option-length | | ||
1845 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1846 | // | IAID (4 octets) | | ||
1847 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1848 | // | T1 | | ||
1849 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1850 | // | T2 | | ||
1851 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1852 | // . . | ||
1853 | // . IA_PD-options . | ||
1854 | // . . | ||
1855 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1793 | if (!client6_data.ia_pd) { | 1856 | if (!client6_data.ia_pd) { |
1794 | bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet"); | 1857 | bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet"); |
1795 | continue; | 1858 | continue; |
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c index 142de9b43..1d7541948 100644 --- a/networking/udhcp/d6_packet.c +++ b/networking/udhcp/d6_packet.c | |||
@@ -153,13 +153,15 @@ int FAST_FUNC d6_send_kernel_packet_from_client_data_ifindex( | |||
153 | } | 153 | } |
154 | setsockopt_reuseaddr(fd); | 154 | setsockopt_reuseaddr(fd); |
155 | 155 | ||
156 | memset(&sa, 0, sizeof(sa)); | 156 | if (src_ipv6) { |
157 | sa.sin6_family = AF_INET6; | 157 | memset(&sa, 0, sizeof(sa)); |
158 | sa.sin6_port = htons(source_port); | 158 | sa.sin6_family = AF_INET6; |
159 | sa.sin6_addr = *src_ipv6; /* struct copy */ | 159 | sa.sin6_port = htons(source_port); |
160 | if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { | 160 | sa.sin6_addr = *src_ipv6; /* struct copy */ |
161 | msg = "bind(%s)"; | 161 | if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { |
162 | goto ret_close; | 162 | msg = "bind(%s)"; |
163 | goto ret_close; | ||
164 | } | ||
163 | } | 165 | } |
164 | 166 | ||
165 | memset(&sa, 0, sizeof(sa)); | 167 | memset(&sa, 0, sizeof(sa)); |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 2904119e5..b9cbd6464 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -575,29 +575,51 @@ static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadc | |||
575 | const uint8_t *chaddr; | 575 | const uint8_t *chaddr; |
576 | uint32_t ciaddr; | 576 | uint32_t ciaddr; |
577 | 577 | ||
578 | // Was: | 578 | // Logic: |
579 | //if (force_broadcast) { /* broadcast */ } | 579 | //if (force_broadcast) { /* broadcast */ } |
580 | //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } | 580 | //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } |
581 | // ^^^ dhcp_pkt->ciaddr comes from client's request packet. | ||
582 | // We expect such clients to have an UDP socket listening on that IP. | ||
581 | //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } | 583 | //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } |
582 | //else { /* unicast to dhcp_pkt->yiaddr */ } | 584 | //else { /* unicast to dhcp_pkt->yiaddr */ } |
583 | // But this is wrong: yiaddr is _our_ idea what client's IP is | 585 | // ^^^ The last case is confusing, but *should* work. |
584 | // (for example, from lease file). Client may not know that, | 586 | // It's a case where client have sent a DISCOVER |
585 | // and may not have UDP socket listening on that IP! | 587 | // and does not have a kernel UDP socket listening on the IP |
586 | // We should never unicast to dhcp_pkt->yiaddr! | 588 | // we are offering in yiaddr (it does not know the IP yet)! |
587 | // dhcp_pkt->ciaddr, OTOH, comes from client's request packet, | 589 | // This *should* work because client *should* listen on a raw socket |
588 | // and can be used. | 590 | // instead at this time (IOW: it should examine ALL IPv4 packets |
589 | 591 | // "by hand", not relying on kernel's UDP stack.) | |
590 | if (force_broadcast | 592 | |
591 | || (dhcp_pkt->flags & htons(BROADCAST_FLAG)) | 593 | chaddr = dhcp_pkt->chaddr; |
592 | || dhcp_pkt->ciaddr == 0 | 594 | |
595 | if (dhcp_pkt->ciaddr == 0 | ||
596 | || force_broadcast /* sending DHCPNAK pkt? */ | ||
593 | ) { | 597 | ) { |
594 | log1s("broadcasting packet to client"); | 598 | if (dhcp_pkt->flags & htons(BROADCAST_FLAG) |
595 | ciaddr = INADDR_BROADCAST; | 599 | || force_broadcast /* sending DHCPNAK pkt? */ |
596 | chaddr = MAC_BCAST_ADDR; | 600 | ) { |
601 | // RFC 2131: | ||
602 | // If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is | ||
603 | // set, then the server broadcasts DHCPOFFER and DHCPACK messages to | ||
604 | // 0xffffffff. ... | ||
605 | // In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK | ||
606 | // messages to 0xffffffff. | ||
607 | ciaddr = INADDR_BROADCAST; | ||
608 | chaddr = MAC_BCAST_ADDR; | ||
609 | log1s("broadcasting packet to client"); | ||
610 | } else { | ||
611 | // If the broadcast bit is not set and 'giaddr' is zero and | ||
612 | // 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK | ||
613 | // messages to the client's hardware address and 'yiaddr' address. | ||
614 | ciaddr = dhcp_pkt->yiaddr; | ||
615 | log1("unicasting packet to client %ciaddr", 'y'); | ||
616 | } | ||
597 | } else { | 617 | } else { |
598 | log1s("unicasting packet to client ciaddr"); | 618 | // If the 'giaddr' |
619 | // field is zero and the 'ciaddr' field is nonzero, then the server | ||
620 | // unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'. | ||
599 | ciaddr = dhcp_pkt->ciaddr; | 621 | ciaddr = dhcp_pkt->ciaddr; |
600 | chaddr = dhcp_pkt->chaddr; | 622 | log1("unicasting packet to client %ciaddr", 'c'); |
601 | } | 623 | } |
602 | 624 | ||
603 | udhcp_send_raw_packet(dhcp_pkt, | 625 | udhcp_send_raw_packet(dhcp_pkt, |
@@ -624,6 +646,10 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt) | |||
624 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) | 646 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) |
625 | { | 647 | { |
626 | if (dhcp_pkt->gateway_nip) | 648 | if (dhcp_pkt->gateway_nip) |
649 | // RFC 2131: | ||
650 | // If the 'giaddr' field in a DHCP message from a client is non-zero, | ||
651 | // the server sends any return messages to the 'DHCP server' port on the | ||
652 | // BOOTP relay agent whose address appears in 'giaddr'. | ||
627 | send_packet_to_relay(dhcp_pkt); | 653 | send_packet_to_relay(dhcp_pkt); |
628 | else | 654 | else |
629 | send_packet_to_client(dhcp_pkt, force_broadcast); | 655 | send_packet_to_client(dhcp_pkt, force_broadcast); |
diff --git a/runit/chpst.c b/runit/chpst.c index 4e3d613b7..3d04ee50d 100644 --- a/runit/chpst.c +++ b/runit/chpst.c | |||
@@ -38,7 +38,8 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
38 | //config: bool "setuidgid (4.2 kb)" | 38 | //config: bool "setuidgid (4.2 kb)" |
39 | //config: default y | 39 | //config: default y |
40 | //config: help | 40 | //config: help |
41 | //config: Sets soft resource limits as specified by options | 41 | //config: Sets UID and GID to those of the given account, and execs |
42 | //config: specified program. | ||
42 | //config: | 43 | //config: |
43 | //config:config ENVUIDGID | 44 | //config:config ENVUIDGID |
44 | //config: bool "envuidgid (4.1 kb)" | 45 | //config: bool "envuidgid (4.1 kb)" |
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh index a608d4c5e..885586865 100755 --- a/scripts/kconfig/lxdialog/check-lxdialog.sh +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh | |||
@@ -53,7 +53,7 @@ trap "rm -f $tmp" 0 1 2 3 15 | |||
53 | check() { | 53 | check() { |
54 | $cc -x c - -o $tmp 2>/dev/null <<'EOF' | 54 | $cc -x c - -o $tmp 2>/dev/null <<'EOF' |
55 | #include CURSES_LOC | 55 | #include CURSES_LOC |
56 | int main() {} | 56 | int main() { return 0; } |
57 | EOF | 57 | EOF |
58 | if [ $? != 0 ]; then | 58 | if [ $? != 0 ]; then |
59 | echo " *** Unable to find the ncurses libraries or the" 1>&2 | 59 | echo " *** Unable to find the ncurses libraries or the" 1>&2 |
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 7558051f0..2cbb22b6d 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c | |||
@@ -1045,7 +1045,7 @@ static int NOINLINE syslogd_init(char **argv) | |||
1045 | #endif | 1045 | #endif |
1046 | /* If they have not specified remote logging, then log locally */ | 1046 | /* If they have not specified remote logging, then log locally */ |
1047 | if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog)) // -R | 1047 | if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog)) // -R |
1048 | option_mask32 |= OPT_locallog; | 1048 | option_mask32 = (opts |= OPT_locallog); |
1049 | #if ENABLE_FEATURE_SYSLOGD_CFG | 1049 | #if ENABLE_FEATURE_SYSLOGD_CFG |
1050 | parse_syslogdcfg(opt_f); | 1050 | parse_syslogdcfg(opt_f); |
1051 | #endif | 1051 | #endif |
diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests index 85e746589..a4462c53e 100755 --- a/testsuite/cpio.tests +++ b/testsuite/cpio.tests | |||
@@ -154,6 +154,29 @@ testing "cpio -R with extract" \ | |||
154 | " "" "" | 154 | " "" "" |
155 | SKIP= | 155 | SKIP= |
156 | 156 | ||
157 | # Create an archive containing a file with "../dont_write" filename. | ||
158 | # See that it will not be allowed to unpack. | ||
159 | # NB: GNU cpio 2.15 DOES NOT do such checks. | ||
160 | optional FEATURE_PATH_TRAVERSAL_PROTECTION | ||
161 | rm -rf cpio.testdir | ||
162 | mkdir -p cpio.testdir/prepare/inner | ||
163 | echo "file outside of destination was written" > cpio.testdir/prepare/dont_write | ||
164 | echo "data" > cpio.testdir/prepare/inner/to_extract | ||
165 | mkdir -p cpio.testdir/extract | ||
166 | testing "cpio extract file outside of destination" "\ | ||
167 | (cd cpio.testdir/prepare/inner && echo -e '../dont_write\nto_extract' | cpio -o -H newc) | (cd cpio.testdir/extract && cpio -vi 2>&1) | ||
168 | echo \$? | ||
169 | ls cpio.testdir/dont_write 2>&1" \ | ||
170 | "\ | ||
171 | cpio: removing leading '../' from member names | ||
172 | ../dont_write | ||
173 | to_extract | ||
174 | 1 blocks | ||
175 | 0 | ||
176 | ls: cpio.testdir/dont_write: No such file or directory | ||
177 | " "" "" | ||
178 | SKIP= | ||
179 | |||
157 | # Clean up | 180 | # Clean up |
158 | rm -rf cpio.testdir cpio.testdir2 2>/dev/null | 181 | rm -rf cpio.testdir cpio.testdir2 2>/dev/null |
159 | 182 | ||