이 절차를 수행하는 이유를 이해할 수 없습니다
#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 쉘에서 호출될 때
echo -e "3\nls\n" | myprogram
ls의 출력을 인쇄하지 마십시오. system("/bin/sh")
호출이 호출자의 표준 입력에서 읽지 않은 것과 같습니다 . 저는 일반 Linux 사용자가 아니므로 system("/bin/sh");
이 설명이 어떻게 작동하는지 더 잘 이해하기 위해 내용을 읽고, 실험을 시도하고, 명령을 실행하는 데 도움이 될 것입니다.
답변1
scanf
그 이유는 표준 입력 스트림에서 읽은 내용을 사용하고 있기 때문입니다 . 버퍼를 사용하므로 실제로 필요한 데이터의 양을 확인하기 전에 데이터 버퍼를 읽으려고 시도합니다. 명령 ls
을 즉시 사용할 수 있으므로 버퍼로 읽어 들여서 다른 scanf 호출(또는 stdin에서 실행되는 다른 버퍼링된 stdio 함수)에 사용되기를 기다립니다. 따라서 sh
stdin에서 읽으려고 할 때 C 프로그램 내부의 버퍼를 볼 수 없기 때문에 아무것도 남지 않습니다.
이 문제를 해결하는 방법에는 최소한 두 가지가 있습니다.
scanf가 읽기를 완료할 때까지 "ls" 명령이 표준 입력에 반영되지 않는지 확인하세요. 프로그램이 해당 지점을 통과했다는 증거를 출력할 때까지 기다려야 하거나(사소하지 않음) 고정된 지연을 사용하고 시스템이 해당 지점에서 멈추지 않고 지연을 너무 짧게 만들지 않기를 바라기 때문에 이는 약간 까다롭습니다(예: 이는 깨지기 쉬운 솔루션입니다). 후자는 다음과 같습니다.
(echo 3 ; sleep 1 ; echo ls) | myprogram
즉, 세 가지 명령이 순서대로 실행되고 모두myprogram
.함수를 사용하여 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");
}