aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-07-13 08:29:09 +0100
committerRon Yorston <rmy@pobox.com>2024-07-13 08:29:09 +0100
commitb18891bba511d4fc4fcd0a6ff5cd2df31a086f1b (patch)
treeef78f9ecc339d6ab95eed03f787f058f270b8772
parent684dabdb8452b3d33d5d6265f3d7ef32c10f5307 (diff)
parent23da5c4b716b92524240c6f81c2e2474c1825cfc (diff)
downloadbusybox-w32-b18891bba511d4fc4fcd0a6ff5cd2df31a086f1b.tar.gz
busybox-w32-b18891bba511d4fc4fcd0a6ff5cd2df31a086f1b.tar.bz2
busybox-w32-b18891bba511d4fc4fcd0a6ff5cd2df31a086f1b.zip
Merge branch 'busybox' into merge
-rw-r--r--coreutils/md5_sha1_sum.c4
-rw-r--r--editors/vi.c7
-rw-r--r--libbb/hash_md5_sha.c29
-rw-r--r--networking/tls_sp_c32.c91
-rw-r--r--shell/ash.c40
-rw-r--r--shell/ash_test/ash-redir/redir3.right2
-rw-r--r--shell/ash_test/ash-redir/redir_exec2.right4
-rwxr-xr-xshell/ash_test/ash-redir/redir_exec2.tests10
-rw-r--r--shell/ash_test/ash-redir/redir_to_bad_fd255.right2
-rw-r--r--shell/ash_test/ash-redir/redir_to_bad_fd3.right2
-rw-r--r--shell/hush.c75
-rw-r--r--shell/hush_test/hush-redir/redir3.right3
-rw-r--r--shell/hush_test/hush-redir/redir_exec2.right4
-rwxr-xr-xshell/hush_test/hush-redir/redir_exec2.tests10
-rw-r--r--shell/hush_test/hush-redir/redir_to_bad_fd.right3
-rw-r--r--shell/hush_test/hush-redir/redir_to_bad_fd255.right3
-rw-r--r--shell/hush_test/hush-redir/redir_to_bad_fd3.right3
17 files changed, 208 insertions, 84 deletions
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
index 15f2c04de..978d328f1 100644
--- a/coreutils/md5_sha1_sum.c
+++ b/coreutils/md5_sha1_sum.c
@@ -320,11 +320,7 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv)
320 320
321 hash_value = hash_file(in_buf, filename_ptr, sha3_width); 321 hash_value = hash_file(in_buf, filename_ptr, sha3_width);
322 322
323#if ENABLE_PLATFORM_MINGW32
324 if (hash_value && (strcasecmp((char*)hash_value, line) == 0)) { 323 if (hash_value && (strcasecmp((char*)hash_value, line) == 0)) {
325#else
326 if (hash_value && (strcmp((char*)hash_value, line) == 0)) {
327#endif
328 if (!(flags & FLAG_SILENT)) 324 if (!(flags & FLAG_SILENT))
329 printf("%s: OK\n", filename_ptr); 325 printf("%s: OK\n", filename_ptr);
330 } else { 326 } else {
diff --git a/editors/vi.c b/editors/vi.c
index 7ad8412a2..e59083ddb 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2422,9 +2422,10 @@ static int init_text_buffer(char *fn)
2422 2422
2423 update_filename(fn); 2423 update_filename(fn);
2424 rc = file_insert(fn, text, 1); 2424 rc = file_insert(fn, text, 1);
2425 if (rc < 0) { 2425 if (rc <= 0 || *(end - 1) != '\n') {
2426 // file doesnt exist. Start empty buf with dummy line 2426 // file doesn't exist or doesn't end in a newline.
2427 char_insert(text, '\n', NO_UNDO); 2427 // insert a newline to the end
2428 char_insert(end, '\n', NO_UNDO);
2428 } 2429 }
2429 2430
2430 flush_undo_data(); 2431 flush_undo_data();
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index 88baf51dc..57a801459 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -15,18 +15,28 @@
15 15
16#if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL 16#if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL
17# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 17# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
18static void cpuid(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) 18static void cpuid_eax_ebx_ecx(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
19{ 19{
20 asm ("cpuid" 20 asm ("cpuid"
21 : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) 21 : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
22 : "0"(*eax), "1"(*ebx), "2"(*ecx), "3"(*edx) 22 : "0" (*eax), "1" (*ebx), "2" (*ecx)
23 ); 23 );
24} 24}
25static smallint shaNI; 25static smallint shaNI;
26static int get_shaNI(void) 26static NOINLINE int get_shaNI(void)
27{ 27{
28 unsigned eax = 7, ebx = ebx, ecx = 0, edx = edx; 28 /* Get leaf 7 subleaf 0. Exists on all CPUs since Merom (2006).
29 cpuid(&eax, &ebx, &ecx, &edx); 29 * "If a value entered for CPUID.EAX is higher than the maximum
30 * input value for basic or extended function for that processor
31 * then the data for the highest basic information leaf is returned".
32 * This means that Pentiums 4 would return leaf 5 or 6 instead of 7,
33 * which happen to have zero in EBX bit 29. Thus they should work too.
34 */
35 unsigned eax = 7;
36 unsigned ecx = 0;
37 unsigned ebx = 0; /* should not be needed, paranoia */
38 unsigned edx;
39 cpuid_eax_ebx_ecx(&eax, &ebx, &ecx, &edx);
30 ebx = ((ebx >> 28) & 2) - 1; /* bit 29 -> 1 or -1 */ 40 ebx = ((ebx >> 28) & 2) - 1; /* bit 29 -> 1 or -1 */
31 shaNI = (int)ebx; 41 shaNI = (int)ebx;
32 return (int)ebx; 42 return (int)ebx;
@@ -1300,7 +1310,14 @@ unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf)
1300 /* SHA stores total in BE, need to swap on LE arches: */ 1310 /* SHA stores total in BE, need to swap on LE arches: */
1301 common64_end(ctx, /*swap_needed:*/ BB_LITTLE_ENDIAN); 1311 common64_end(ctx, /*swap_needed:*/ BB_LITTLE_ENDIAN);
1302 1312
1303 hash_size = (ctx->process_block == sha1_process_block64) ? 5 : 8; 1313 hash_size = 8;
1314 if (ctx->process_block == sha1_process_block64
1315#if ENABLE_SHA1_HWACCEL
1316 || ctx->process_block == sha1_process_block64_shaNI
1317#endif
1318 ) {
1319 hash_size = 5;
1320 }
1304 /* This way we do not impose alignment constraints on resbuf: */ 1321 /* This way we do not impose alignment constraints on resbuf: */
1305 if (BB_LITTLE_ENDIAN) { 1322 if (BB_LITTLE_ENDIAN) {
1306 unsigned i; 1323 unsigned i;
diff --git a/networking/tls_sp_c32.c b/networking/tls_sp_c32.c
index 999033034..e493c436a 100644
--- a/networking/tls_sp_c32.c
+++ b/networking/tls_sp_c32.c
@@ -411,10 +411,10 @@ static void sp_256_sub_8_p256_mod(sp_digit* r)
411"\n subl $0xffffffff, (%0)" 411"\n subl $0xffffffff, (%0)"
412"\n sbbl $0xffffffff, 1*4(%0)" 412"\n sbbl $0xffffffff, 1*4(%0)"
413"\n sbbl $0xffffffff, 2*4(%0)" 413"\n sbbl $0xffffffff, 2*4(%0)"
414"\n sbbl $0, 3*4(%0)" 414"\n sbbl $0x00000000, 3*4(%0)"
415"\n sbbl $0, 4*4(%0)" 415"\n sbbl $0x00000000, 4*4(%0)"
416"\n sbbl $0, 5*4(%0)" 416"\n sbbl $0x00000000, 5*4(%0)"
417"\n sbbl $1, 6*4(%0)" 417"\n sbbl $0x00000001, 6*4(%0)"
418"\n sbbl $0xffffffff, 7*4(%0)" 418"\n sbbl $0xffffffff, 7*4(%0)"
419"\n" 419"\n"
420 : "=r" (r) 420 : "=r" (r)
@@ -422,29 +422,48 @@ static void sp_256_sub_8_p256_mod(sp_digit* r)
422 : "memory" 422 : "memory"
423 ); 423 );
424} 424}
425#elif ALLOW_ASM && defined(__GNUC__) && defined(__x86_64__) && ENABLE_PLATFORM_POSIX 425#elif ALLOW_ASM && defined(__GNUC__) && defined(__x86_64__)
426static void sp_256_sub_8_p256_mod(sp_digit* r) 426static void sp_256_sub_8_p256_mod(sp_digit* r)
427{ 427{
428//p256_mod[3..0] = ffffffff00000001 0000000000000000 00000000ffffffff ffffffffffffffff
429# if 0
430 // gcc -Oz bug (?) https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115875
431 // uses buggy "push $-1; pop %rax" insns to load 00000000ffffffff
428 uint64_t reg; 432 uint64_t reg;
429 uint64_t ooff; 433 uint64_t ooff;
430//p256_mod[3..0] = ffffffff00000001 0000000000000000 00000000ffffffff ffffffffffffffff
431 asm volatile ( 434 asm volatile (
432"\n addq $1, (%0)" // adding 1 is the same as subtracting ffffffffffffffff 435"\n subq $0xffffffffffffffff, (%0)"
433"\n cmc" // only carry bit needs inverting 436"\n sbbq %1, 1*8(%0)" // %1 = 00000000ffffffff
434"\n" 437"\n sbbq $0x0000000000000000, 2*8(%0)"
435"\n sbbq %1, 1*8(%0)" // %1 holds 00000000ffffffff
436"\n"
437"\n sbbq $0, 2*8(%0)"
438"\n"
439"\n movq 3*8(%0), %2" 438"\n movq 3*8(%0), %2"
440"\n sbbq $0, %2" // adding 00000000ffffffff (in %1) 439"\n sbbq $0x0, %2" // subtract carry
441"\n addq %1, %2" // is the same as subtracting ffffffff00000001 440"\n addq %1, %2" // adding 00000000ffffffff (in %1)
441"\n" // is the same as subtracting ffffffff00000001
442"\n movq %2, 3*8(%0)" 442"\n movq %2, 3*8(%0)"
443"\n" 443"\n"
444 : "=r" (r), "=r" (ooff), "=r" (reg) 444 : "=r" (r), "=r" (ooff), "=r" (reg)
445 : "0" (r), "1" (0x00000000ffffffff) 445 : "0" (r), "1" (0x00000000ffffffffUL) /* UL is important! */
446 : "memory"
447 );
448# else // let's do it by hand:
449 uint64_t reg;
450 uint64_t rax;
451 asm volatile (
452"\n orl $0xffffffff, %%eax" // %1 (rax) = 00000000ffffffff
453"\n subq $0xffffffffffffffff, (%0)"
454"\n sbbq %1, 1*8(%0)"
455"\n sbbq $0x0000000000000000, 2*8(%0)"
456"\n movq 3*8(%0), %2"
457"\n sbbq $0x0, %2" // subtract carry
458"\n addq %1, %2" // adding 00000000ffffffff (in %1)
459"\n" // is the same as subtracting ffffffff00000001
460"\n movq %2, 3*8(%0)"
461"\n"
462 : "=r" (r), "=&a" (rax), "=r" (reg)
463 : "0" (r)
446 : "memory" 464 : "memory"
447 ); 465 );
466# endif
448} 467}
449#else 468#else
450static void sp_256_sub_8_p256_mod(sp_digit* r) 469static void sp_256_sub_8_p256_mod(sp_digit* r)
@@ -476,15 +495,23 @@ static void sp_256to512_mul_8(sp_digit* r, const sp_digit* a, const sp_digit* b)
476//////////////////////// 495////////////////////////
477// uint64_t m = ((uint64_t)a[i]) * b[j]; 496// uint64_t m = ((uint64_t)a[i]) * b[j];
478// acc_hi:acch:accl += m; 497// acc_hi:acch:accl += m;
498 long eax_clobbered;
479 asm volatile ( 499 asm volatile (
480 // a[i] is already loaded in %%eax 500 // a[i] is already loaded in %%eax
481"\n mull %7" 501"\n mull %8"
482"\n addl %%eax, %0" 502"\n addl %%eax, %0"
483"\n adcl %%edx, %1" 503"\n adcl %%edx, %1"
484"\n adcl $0, %2" 504"\n adcl $0x0, %2"
485 : "=rm" (accl), "=rm" (acch), "=rm" (acc_hi) 505 : "=rm" (accl), "=rm" (acch), "=rm" (acc_hi), "=a" (eax_clobbered)
486 : "0" (accl), "1" (acch), "2" (acc_hi), "a" (a[i]), "m" (b[j]) 506 : "0" (accl), "1" (acch), "2" (acc_hi), "3" (a[i]), "m" (b[j])
487 : "cc", "dx" 507 : "cc", "dx"
508// What is "eax_clobbered"? gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html:
509// "Do not modify the contents of input-only operands (except for inputs tied
510// to outputs). The compiler assumes that on exit from the asm statement these
511// operands contain the same values as they had before executing the statement.
512// It is not possible to use clobbers to inform the compiler that the values
513// in these inputs are changing. One common work-around is to tie the changing
514// input variable to an output variable that never gets used."
488 ); 515 );
489//////////////////////// 516////////////////////////
490 j--; 517 j--;
@@ -500,15 +527,20 @@ static void sp_256to512_mul_8(sp_digit* r, const sp_digit* a, const sp_digit* b)
500 const uint64_t* bb = (const void*)b; 527 const uint64_t* bb = (const void*)b;
501 uint64_t* rr = (void*)r; 528 uint64_t* rr = (void*)r;
502 int k; 529 int k;
503 uint64_t accl; 530 register uint64_t accl asm("r8");
504 uint64_t acch; 531 register uint64_t acch asm("r9");
532 /* ^^^ ask gcc to not use rax/rdx/input arg regs for accumulator variables */
533 /* (or else it may generate lots of silly mov's and even xchg's!) */
505 534
506 acch = accl = 0; 535 acch = accl = 0;
507 for (k = 0; k < 7; k++) { 536 for (k = 0; k < 7; k++) {
508 int i, j; 537 unsigned i, j;
509 uint64_t acc_hi; 538 /* ^^^^^ not signed "int",
539 * or gcc can use a temp register to sign-extend i,j for aa[i],bb[j] */
540 register uint64_t acc_hi asm("r10");
541 /* ^^^ ask gcc to not use rax/rdx/input arg regs for accumulators */
510 i = k - 3; 542 i = k - 3;
511 if (i < 0) 543 if ((int)i < 0)
512 i = 0; 544 i = 0;
513 j = k - i; 545 j = k - i;
514 acc_hi = 0; 546 acc_hi = 0;
@@ -516,14 +548,15 @@ static void sp_256to512_mul_8(sp_digit* r, const sp_digit* a, const sp_digit* b)
516//////////////////////// 548////////////////////////
517// uint128_t m = ((uint128_t)a[i]) * b[j]; 549// uint128_t m = ((uint128_t)a[i]) * b[j];
518// acc_hi:acch:accl += m; 550// acc_hi:acch:accl += m;
551 long rax_clobbered;
519 asm volatile ( 552 asm volatile (
520 // aa[i] is already loaded in %%rax 553 // aa[i] is already loaded in %%rax
521"\n mulq %7" 554"\n mulq %8"
522"\n addq %%rax, %0" 555"\n addq %%rax, %0"
523"\n adcq %%rdx, %1" 556"\n adcq %%rdx, %1"
524"\n adcq $0, %2" 557"\n adcq $0x0, %2"
525 : "=rm" (accl), "=rm" (acch), "=rm" (acc_hi) 558 : "=rm" (accl), "=rm" (acch), "=rm" (acc_hi), "=a" (rax_clobbered)
526 : "0" (accl), "1" (acch), "2" (acc_hi), "a" (aa[i]), "m" (bb[j]) 559 : "0" (accl), "1" (acch), "2" (acc_hi), "3" (aa[i]), "m" (bb[j])
527 : "cc", "dx" 560 : "cc", "dx"
528 ); 561 );
529//////////////////////// 562////////////////////////
diff --git a/shell/ash.c b/shell/ash.c
index 719f722a2..7a9f20ec0 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -758,10 +758,9 @@ static void trace_vprintf(const char *fmt, va_list va);
758#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 758#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
759 759
760static int 760static int
761isdigit_str9(const char *str) 761isdigit_str(const char *str)
762{ 762{
763 int maxlen = 9 + 1; /* max 9 digits: 999999999 */ 763 while (isdigit(*str))
764 while (--maxlen && isdigit(*str))
765 str++; 764 str++;
766 return (*str == '\0'); 765 return (*str == '\0');
767} 766}
@@ -6386,10 +6385,13 @@ dup2_or_raise(int from, int to)
6386 newfd = (from != to) ? dup2(from, to) : to; 6385 newfd = (from != to) ? dup2(from, to) : to;
6387 if (newfd < 0) { 6386 if (newfd < 0) {
6388 /* Happens when source fd is not open: try "echo >&99" */ 6387 /* Happens when source fd is not open: try "echo >&99" */
6389 ash_msg_and_raise_perror("%d", from); 6388 ash_msg_and_raise_perror("dup2(%d,%d)", from, to);
6390 } 6389 }
6391 return newfd; 6390 return newfd;
6392} 6391}
6392/* The only possible error return is EBADF (fd wasn't open).
6393 * Transient errors retry, other errors raise exception.
6394 */
6393static int 6395static int
6394dup_CLOEXEC(int fd, int avoid_fd) 6396dup_CLOEXEC(int fd, int avoid_fd)
6395{ 6397{
@@ -6404,6 +6406,16 @@ dup_CLOEXEC(int fd, int avoid_fd)
6404 goto repeat; 6406 goto repeat;
6405 if (errno == EINTR) 6407 if (errno == EINTR)
6406 goto repeat; 6408 goto repeat;
6409 if (errno != EBADF) {
6410 /* "echo >&9999" gets EINVAL trying to save fd 1 to above 9999.
6411 * We could try saving it _below_ 9999 instead (how?), but
6412 * this probably means that dup2(9999,1) to effectuate >&9999
6413 * would also not work: fd 9999 can't exist. Gracefully bail out.
6414 * (This differs from "echo >&99" where saving works, but
6415 * subsequent dup2(99,1) fails if fd 99 is not open).
6416 */
6417 ash_msg_and_raise_perror("fcntl(%d,F_DUPFD,%d)", fd, avoid_fd + 1);
6418 }
6407 } 6419 }
6408 return newfd; 6420 return newfd;
6409} 6421}
@@ -6519,7 +6531,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
6519 new_fd = dup_CLOEXEC(fd, avoid_fd); 6531 new_fd = dup_CLOEXEC(fd, avoid_fd);
6520 sq->two_fd[i].moved_to = new_fd; 6532 sq->two_fd[i].moved_to = new_fd;
6521 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd)); 6533 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
6522 if (new_fd < 0) /* what? */ 6534 if (new_fd < 0) /* EBADF? what? */
6523 xfunc_die(); 6535 xfunc_die();
6524 return 0; /* "we did not close fd" */ 6536 return 0; /* "we did not close fd" */
6525 } 6537 }
@@ -6534,8 +6546,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
6534 new_fd = dup_CLOEXEC(fd, avoid_fd); 6546 new_fd = dup_CLOEXEC(fd, avoid_fd);
6535 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd)); 6547 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
6536 if (new_fd < 0) { 6548 if (new_fd < 0) {
6537 if (errno != EBADF) 6549 /* EBADF (fd is not open) */
6538 xfunc_die();
6539 /* new_fd = CLOSED; - already is -1 */ 6550 /* new_fd = CLOSED; - already is -1 */
6540 } 6551 }
6541 sq->two_fd[i].moved_to = new_fd; 6552 sq->two_fd[i].moved_to = new_fd;
@@ -10767,7 +10778,7 @@ expredir(union node *n)
10767 if (fn.list == NULL) 10778 if (fn.list == NULL)
10768 ash_msg_and_raise_error("redir error"); 10779 ash_msg_and_raise_error("redir error");
10769#if BASH_REDIR_OUTPUT 10780#if BASH_REDIR_OUTPUT
10770 if (!isdigit_str9(fn.list->text)) { 10781 if (!isdigit_str(fn.list->text)) {
10771 /* >&file, not >&fd */ 10782 /* >&file, not >&fd */
10772 if (redir->nfile.fd != 1) /* 123>&file - BAD */ 10783 if (redir->nfile.fd != 1) /* 123>&file - BAD */
10773 ash_msg_and_raise_error("redir error"); 10784 ash_msg_and_raise_error("redir error");
@@ -13284,12 +13295,19 @@ fixredir(union node *n, const char *text, int err)
13284 if (!err) 13295 if (!err)
13285 n->ndup.vname = NULL; 13296 n->ndup.vname = NULL;
13286 13297
13298 if (LONE_DASH(text)) {
13299 n->ndup.dupfd = -1;
13300 return;
13301 }
13302
13287 fd = bb_strtou(text, NULL, 10); 13303 fd = bb_strtou(text, NULL, 10);
13288 if (!errno && fd >= 0) 13304 if (!errno && fd >= 0)
13289 n->ndup.dupfd = fd; 13305 n->ndup.dupfd = fd;
13290 else if (LONE_DASH(text))
13291 n->ndup.dupfd = -1;
13292 else { 13306 else {
13307 /* This also fails on very large numbers
13308 * which overflow "int" - bb_strtou() does not
13309 * silently truncate results to word width.
13310 */
13293 if (err) 13311 if (err)
13294 raise_error_syntax("bad fd number"); 13312 raise_error_syntax("bad fd number");
13295 n->ndup.vname = makename(); 13313 n->ndup.vname = makename();
@@ -13975,7 +13993,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
13975 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>')) 13993 if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>'))
13976 && quotef == 0 13994 && quotef == 0
13977 ) { 13995 ) {
13978 if (isdigit_str9(out)) { 13996 if (isdigit_str(out)) {
13979 PARSEREDIR(); /* passed as params: out, c */ 13997 PARSEREDIR(); /* passed as params: out, c */
13980 lasttoken = TREDIR; 13998 lasttoken = TREDIR;
13981 return lasttoken; 13999 return lasttoken;
diff --git a/shell/ash_test/ash-redir/redir3.right b/shell/ash_test/ash-redir/redir3.right
index fd641a8ea..d9cf5dac5 100644
--- a/shell/ash_test/ash-redir/redir3.right
+++ b/shell/ash_test/ash-redir/redir3.right
@@ -1,3 +1,3 @@
1TEST 1TEST
2./redir3.tests: line 4: 9: Bad file descriptor 2./redir3.tests: line 4: dup2(9,1): Bad file descriptor
3Output to fd#9: 1 3Output to fd#9: 1
diff --git a/shell/ash_test/ash-redir/redir_exec2.right b/shell/ash_test/ash-redir/redir_exec2.right
new file mode 100644
index 000000000..2bdc093c9
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_exec2.right
@@ -0,0 +1,4 @@
1fd/5
2fd/4
3fd/3
4One:1
diff --git a/shell/ash_test/ash-redir/redir_exec2.tests b/shell/ash_test/ash-redir/redir_exec2.tests
new file mode 100755
index 000000000..0af767592
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_exec2.tests
@@ -0,0 +1,10 @@
1cd /proc/$$
2exec 5>/dev/null
3exec 4>/dev/null
4exec 3>/dev/null
5ls -1 fd/5
6ls -1 fd/4
7ls -1 fd/3
8exec 5>&-
9test -e fd/5 && echo BUG
10echo One:$?
diff --git a/shell/ash_test/ash-redir/redir_to_bad_fd255.right b/shell/ash_test/ash-redir/redir_to_bad_fd255.right
index 9c5e35b36..ca4df91ac 100644
--- a/shell/ash_test/ash-redir/redir_to_bad_fd255.right
+++ b/shell/ash_test/ash-redir/redir_to_bad_fd255.right
@@ -1,2 +1,2 @@
1./redir_to_bad_fd255.tests: line 2: 255: Bad file descriptor 1./redir_to_bad_fd255.tests: line 2: dup2(255,1): Bad file descriptor
2OK 2OK
diff --git a/shell/ash_test/ash-redir/redir_to_bad_fd3.right b/shell/ash_test/ash-redir/redir_to_bad_fd3.right
index 895a4a0a6..5120322a5 100644
--- a/shell/ash_test/ash-redir/redir_to_bad_fd3.right
+++ b/shell/ash_test/ash-redir/redir_to_bad_fd3.right
@@ -1,2 +1,2 @@
1./redir_to_bad_fd3.tests: line 2: 3: Bad file descriptor 1./redir_to_bad_fd3.tests: line 2: dup2(3,1): Bad file descriptor
2OK 2OK
diff --git a/shell/hush.c b/shell/hush.c
index 3e6a13b32..707b77c9c 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1575,12 +1575,22 @@ static int dup_CLOEXEC(int fd, int avoid_fd)
1575 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1); 1575 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1576 if (newfd >= 0) { 1576 if (newfd >= 0) {
1577 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */ 1577 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
1578 fcntl(newfd, F_SETFD, FD_CLOEXEC); 1578 close_on_exec_on(newfd);
1579 } else { /* newfd < 0 */ 1579 } else { /* newfd < 0 */
1580 if (errno == EBUSY) 1580 if (errno == EBUSY)
1581 goto repeat; 1581 goto repeat;
1582 if (errno == EINTR) 1582 if (errno == EINTR)
1583 goto repeat; 1583 goto repeat;
1584 if (errno != EBADF) {
1585 /* "echo >&9999" gets EINVAL trying to save fd 1 to above 9999.
1586 * We could try saving it _below_ 9999 instead (how?), but
1587 * this probably means that dup2(9999,1) to effectuate >&9999
1588 * would also not work: fd 9999 can't exist.
1589 * (This differs from "echo >&99" where saving works, but
1590 * subsequent dup2(99,1) fails if fd 99 is not open).
1591 */
1592 bb_perror_msg("fcntl(%d,F_DUPFD,%d)", fd, avoid_fd + 1);
1593 }
1584 } 1594 }
1585 return newfd; 1595 return newfd;
1586} 1596}
@@ -1601,7 +1611,7 @@ static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
1601 xfunc_die(); 1611 xfunc_die();
1602 } 1612 }
1603 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */ 1613 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
1604 fcntl(newfd, F_SETFD, FD_CLOEXEC); 1614 close_on_exec_on(newfd);
1605 close(fd); 1615 close(fd);
1606 return newfd; 1616 return newfd;
1607} 1617}
@@ -7893,10 +7903,16 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
7893 if (sq) for (; sq[i].orig_fd >= 0; i++) { 7903 if (sq) for (; sq[i].orig_fd >= 0; i++) {
7894 /* If we collide with an already moved fd... */ 7904 /* If we collide with an already moved fd... */
7895 if (fd == sq[i].moved_to) { 7905 if (fd == sq[i].moved_to) {
7896 sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd); 7906 moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd);
7897 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to); 7907 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, moved_to);
7898 if (sq[i].moved_to < 0) /* what? */ 7908 if (moved_to < 0) {
7899 xfunc_die(); 7909 /* "echo 2>/dev/tty 10>&9999" testcase:
7910 * We move fd 2 to 10, then discover we need to move fd 10
7911 * (and not hit 9999) and the latter fails.
7912 */
7913 return NULL; /* fcntl failed */
7914 }
7915 sq[i].moved_to = moved_to;
7900 return sq; 7916 return sq;
7901 } 7917 }
7902 if (fd == sq[i].orig_fd) { 7918 if (fd == sq[i].orig_fd) {
@@ -7910,7 +7926,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
7910 moved_to = dup_CLOEXEC(fd, avoid_fd); 7926 moved_to = dup_CLOEXEC(fd, avoid_fd);
7911 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to); 7927 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
7912 if (moved_to < 0 && errno != EBADF) 7928 if (moved_to < 0 && errno != EBADF)
7913 xfunc_die(); 7929 return NULL; /* fcntl failed (not because fd is closed) */
7914 return append_squirrel(sq, i, fd, moved_to); 7930 return append_squirrel(sq, i, fd, moved_to);
7915} 7931}
7916 7932
@@ -7943,6 +7959,8 @@ static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd)
7943 */ 7959 */
7944static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) 7960static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7945{ 7961{
7962 struct squirrel *new_squirrel;
7963
7946 if (avoid_fd < 9) /* the important case here is that it can be -1 */ 7964 if (avoid_fd < 9) /* the important case here is that it can be -1 */
7947 avoid_fd = 9; 7965 avoid_fd = 9;
7948 7966
@@ -8006,7 +8024,10 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
8006 } 8024 }
8007 8025
8008 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */ 8026 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
8009 *sqp = add_squirrel(*sqp, fd, avoid_fd); 8027 new_squirrel = add_squirrel(*sqp, fd, avoid_fd);
8028 if (!new_squirrel)
8029 return -1; /* redirect error */
8030 *sqp = new_squirrel;
8010 return 0; /* "we did not close fd" */ 8031 return 0; /* "we did not close fd" */
8011} 8032}
8012 8033
@@ -8077,8 +8098,11 @@ static int internally_opened_fd(int fd, struct squirrel *sq)
8077 return 0; 8098 return 0;
8078} 8099}
8079 8100
8080/* squirrel != NULL means we squirrel away copies of stdin, stdout, 8101/* sqp != NULL means we squirrel away copies of stdin, stdout,
8081 * and stderr if they are redirected. */ 8102 * and stderr if they are redirected.
8103 * If redirection fails, return 1. This will make caller
8104 * skip command execution and restore already created redirect fds.
8105 */
8082static int setup_redirects(struct command *prog, struct squirrel **sqp) 8106static int setup_redirects(struct command *prog, struct squirrel **sqp)
8083{ 8107{
8084 struct redir_struct *redir; 8108 struct redir_struct *redir;
@@ -8089,7 +8113,8 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
8089 8113
8090 if (redir->rd_type == REDIRECT_HEREDOC2) { 8114 if (redir->rd_type == REDIRECT_HEREDOC2) {
8091 /* "rd_fd<<HERE" case */ 8115 /* "rd_fd<<HERE" case */
8092 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp); 8116 if (save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp) < 0)
8117 return 1;
8093 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 8118 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
8094 * of the heredoc */ 8119 * of the heredoc */
8095 debug_printf_redir("set heredoc '%s'\n", 8120 debug_printf_redir("set heredoc '%s'\n",
@@ -8109,7 +8134,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
8109 * "cmd > <file" (2nd redirect starts too early) 8134 * "cmd > <file" (2nd redirect starts too early)
8110 */ 8135 */
8111 syntax_error("invalid redirect"); 8136 syntax_error("invalid redirect");
8112 continue; 8137 return 1;
8113 } 8138 }
8114 mode = redir_table[redir->rd_type].mode; 8139 mode = redir_table[redir->rd_type].mode;
8115 p = expand_string_to_string(redir->rd_filename, 8140 p = expand_string_to_string(redir->rd_filename,
@@ -8124,7 +8149,9 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
8124 */ 8149 */
8125 return 1; 8150 return 1;
8126 } 8151 }
8127 if (newfd == redir->rd_fd && sqp) { 8152 if (newfd == redir->rd_fd && sqp
8153 && sqp != ERR_PTR /* not a redirect in "exec" */
8154 ) {
8128 /* open() gave us precisely the fd we wanted. 8155 /* open() gave us precisely the fd we wanted.
8129 * This means that this fd was not busy 8156 * This means that this fd was not busy
8130 * (not opened to anywhere). 8157 * (not opened to anywhere).
@@ -8146,6 +8173,8 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
8146 /* if "N>&-": close redir->rd_fd (newfd is REDIRFD_CLOSE) */ 8173 /* if "N>&-": close redir->rd_fd (newfd is REDIRFD_CLOSE) */
8147 8174
8148 closed = save_fd_on_redirect(redir->rd_fd, /*avoid:*/ newfd, sqp); 8175 closed = save_fd_on_redirect(redir->rd_fd, /*avoid:*/ newfd, sqp);
8176 if (closed < 0)
8177 return 1; /* error */
8149 if (newfd == REDIRFD_CLOSE) { 8178 if (newfd == REDIRFD_CLOSE) {
8150 /* "N>&-" means "close me" */ 8179 /* "N>&-" means "close me" */
8151 if (!closed) { 8180 if (!closed) {
@@ -8159,13 +8188,16 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
8159 * and second redirect closes 3! Restore code then closes 3 again. 8188 * and second redirect closes 3! Restore code then closes 3 again.
8160 */ 8189 */
8161 } else { 8190 } else {
8162 /* if newfd is a script fd or saved fd, simulate EBADF */ 8191 /* if newfd is a script fd or saved fd, do not allow to use it */
8163 if (internally_opened_fd(newfd, sqp && sqp != ERR_PTR ? *sqp : NULL)) { 8192 if (internally_opened_fd(newfd, sqp && sqp != ERR_PTR ? *sqp : NULL)) {
8164 //errno = EBADF; 8193 bb_error_msg("fd#%d is not open", newfd);
8165 //bb_perror_msg_and_die("can't duplicate file descriptor"); 8194 return 1;
8166 newfd = -1; /* same effect as code above */ 8195 }
8196 if (dup2(newfd, redir->rd_fd) < 0) {
8197 /* "echo >&99" testcase */
8198 bb_perror_msg("dup2(%d,%d)", newfd, redir->rd_fd);
8199 return 1;
8167 } 8200 }
8168 xdup2(newfd, redir->rd_fd);
8169 if (redir->rd_dup == REDIRFD_TO_FILE) 8201 if (redir->rd_dup == REDIRFD_TO_FILE)
8170 /* "rd_fd > FILE" */ 8202 /* "rd_fd > FILE" */
8171 close(newfd); 8203 close(newfd);
@@ -10710,7 +10742,7 @@ int hush_main(int argc, char **argv)
10710 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); 10742 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
10711 if (G_interactive_fd < 0) { 10743 if (G_interactive_fd < 0) {
10712 /* try to dup to any fd */ 10744 /* try to dup to any fd */
10713 G_interactive_fd = dup(STDIN_FILENO); 10745 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1);
10714 if (G_interactive_fd < 0) { 10746 if (G_interactive_fd < 0) {
10715 /* give up */ 10747 /* give up */
10716 G_interactive_fd = 0; 10748 G_interactive_fd = 0;
@@ -10720,8 +10752,6 @@ int hush_main(int argc, char **argv)
10720 } 10752 }
10721 debug_printf("interactive_fd:%d\n", G_interactive_fd); 10753 debug_printf("interactive_fd:%d\n", G_interactive_fd);
10722 if (G_interactive_fd) { 10754 if (G_interactive_fd) {
10723 close_on_exec_on(G_interactive_fd);
10724
10725 if (G_saved_tty_pgrp) { 10755 if (G_saved_tty_pgrp) {
10726 /* If we were run as 'hush &', sleep until we are 10756 /* If we were run as 'hush &', sleep until we are
10727 * in the foreground (tty pgrp == our pgrp). 10757 * in the foreground (tty pgrp == our pgrp).
@@ -10796,9 +10826,6 @@ int hush_main(int argc, char **argv)
10796 G_interactive_fd = 0; 10826 G_interactive_fd = 0;
10797 } 10827 }
10798 } 10828 }
10799 if (G_interactive_fd) {
10800 close_on_exec_on(G_interactive_fd);
10801 }
10802 install_special_sighandlers(); 10829 install_special_sighandlers();
10803#else 10830#else
10804 /* We have interactiveness code disabled */ 10831 /* We have interactiveness code disabled */
diff --git a/shell/hush_test/hush-redir/redir3.right b/shell/hush_test/hush-redir/redir3.right
index e3c878b7d..d49237c42 100644
--- a/shell/hush_test/hush-redir/redir3.right
+++ b/shell/hush_test/hush-redir/redir3.right
@@ -1,2 +1,3 @@
1TEST 1TEST
2hush: can't duplicate file descriptor: Bad file descriptor 2hush: dup2(9,1): Bad file descriptor
3Output to fd#9: 1
diff --git a/shell/hush_test/hush-redir/redir_exec2.right b/shell/hush_test/hush-redir/redir_exec2.right
new file mode 100644
index 000000000..2bdc093c9
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_exec2.right
@@ -0,0 +1,4 @@
1fd/5
2fd/4
3fd/3
4One:1
diff --git a/shell/hush_test/hush-redir/redir_exec2.tests b/shell/hush_test/hush-redir/redir_exec2.tests
new file mode 100755
index 000000000..0af767592
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_exec2.tests
@@ -0,0 +1,10 @@
1cd /proc/$$
2exec 5>/dev/null
3exec 4>/dev/null
4exec 3>/dev/null
5ls -1 fd/5
6ls -1 fd/4
7ls -1 fd/3
8exec 5>&-
9test -e fd/5 && echo BUG
10echo One:$?
diff --git a/shell/hush_test/hush-redir/redir_to_bad_fd.right b/shell/hush_test/hush-redir/redir_to_bad_fd.right
index 936911ce5..4fc51cc93 100644
--- a/shell/hush_test/hush-redir/redir_to_bad_fd.right
+++ b/shell/hush_test/hush-redir/redir_to_bad_fd.right
@@ -1 +1,2 @@
1hush: can't duplicate file descriptor: Bad file descriptor 1hush: dup2(10,1): Bad file descriptor
2OK
diff --git a/shell/hush_test/hush-redir/redir_to_bad_fd255.right b/shell/hush_test/hush-redir/redir_to_bad_fd255.right
index 936911ce5..baa2959ca 100644
--- a/shell/hush_test/hush-redir/redir_to_bad_fd255.right
+++ b/shell/hush_test/hush-redir/redir_to_bad_fd255.right
@@ -1 +1,2 @@
1hush: can't duplicate file descriptor: Bad file descriptor 1hush: dup2(255,1): Bad file descriptor
2OK
diff --git a/shell/hush_test/hush-redir/redir_to_bad_fd3.right b/shell/hush_test/hush-redir/redir_to_bad_fd3.right
index 936911ce5..5e54abc0a 100644
--- a/shell/hush_test/hush-redir/redir_to_bad_fd3.right
+++ b/shell/hush_test/hush-redir/redir_to_bad_fd3.right
@@ -1 +1,2 @@
1hush: can't duplicate file descriptor: Bad file descriptor 1hush: fd#3 is not open
2OK