问题理解系统(“/bin/sh”)

问题理解系统(“/bin/sh”)

我无法理解为什么要执行此程序

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int iRetval = 0;
    unsigned int uiNum;

    printf("Enter number: ");
    fflush(stdout);
    iRetval = scanf("%u", &uiNum);
    printf("\nThe number is %u, Retval: %i\n", uiNum, iRetval);
    fflush(stdout);
    if( iRetval > 0)
        system("/bin/sh");
    else
        printf("Goodbye!\n");
}

当从我的 bash shell 调用时

echo -e "3\nls\n" | myprogram

不打印 ls 的输出。就好像system("/bin/sh")调用没有从调用者的 stdin 读取一样。我不是一个普通的 Linux 用户,所以任何关于阅读内容、尝试实验或运行命令以更好地理解该system("/bin/sh");语句如何工作的帮助都会非常有帮助。

答案1

原因是您正在使用scanf从标准输入流读取的内容。它使用缓冲区,因此它将尝试读取一个缓冲区的数据,然后才检查它真正需要多少数据。由于您的ls命令立即可用,因此它也会被读入缓冲区,等待再次调用 scanf (或在 stdin 上运行的任何其他缓冲 stdio 函数)来使用。因此,当sh尝试从 stdin 读取时,不会剩下任何内容,因为它看不到 C 程序内部的缓冲区。

至少有两种方法可以解决这个问题。

  1. 确保在 scanf 完成读取之前“ls”命令不会回显到标准输入。这有点棘手,因为您需要等待程序输出已经超过该点的证据(不是微不足道的),或者然后使用一些固定延迟并希望系统永远不会在该点停止并使延迟太短(即这是一个脆弱的解决方案)。后者看起来像:(echo 3 ; sleep 1 ; echo ls) | myprogram即三个命令按顺序执行,并且都向myprogram.

  2. 您可以使用函数从 stdin 读取(无需缓冲区)所需的最少字符数。例如,该read函数不使用缓冲区。您可以编写一个辅助函数,例如

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>

int unbuffered_scanf(const char *fmt, ...) {
  char buffer[100]; // maximum line length
  int i;
  int ret;
  for(i=0; i<sizeof(buffer)-1; ++i) {
    if (!read(0, &buffer[i], 1)) break;
    if (buffer[i] == '\n') break;
  }
  buffer[i] = '\0';
  va_list ap;
  va_start(ap, fmt);
  ret = vsscanf(buffer, fmt, ap);
  va_end(ap);
  return ret;
}

int main()
{
    int iRetval = 0;
    unsigned int uiNum;

    printf("Enter number: ");
    fflush(stdout);
    iRetval = unbuffered_scanf("%u", &uiNum);
    printf("\nThe number is %u, Retval: %i\n", uiNum, iRetval);
    fflush(stdout);
    if( iRetval > 0)
        system("/bin/sh");
    else
        printf("Goodbye!\n");
}

有关无缓冲函数的更多信息,请阅读此处的信息页面:https://www.gnu.org/software/libc/manual/html_node/I_002fO-Primitives.html#I_002fO-Primitives

编辑:显然有一种方法可以禁用由scanf其他人使用例如该setbuf函数完成的缓冲 - 它可能在内部工作与我上面的示例完全相同:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int iRetval = 0;
    unsigned int uiNum;

    setbuf(stdin, NULL);
    printf("Enter number: ");
    fflush(stdout);
    iRetval = scanf("%u", &uiNum);
    printf("\nThe number is %u, Retval: %i\n", uiNum, iRetval);
    fflush(stdout);
    if( iRetval > 0)
        system("/bin/sh");
    else
        printf("Goodbye!\n");
}

相关内容