source

strncpy가 null로 종료되지 않는 이유는 무엇입니까?

factcode 2022. 8. 21. 14:06
반응형

strncpy가 null로 종료되지 않는 이유는 무엇입니까?

strncpy()버퍼 오버플로우로부터 보호합니다.그러나 null을 종료하지 않고 오버플로우를 방지하면 후속 문자열 작업이 오버플로우될 가능성이 높습니다.이를 방지하기 위해 저는 다음과 같은 일을 하고 있습니다.

strncpy( dest, src, LEN );
dest[LEN - 1] = '\0';

man strncpy다음과 같은 기능이 있습니다.

strncpy()함수는 비슷하지만 그 이상은 아니다.n바이트 수src복사됩니다.따라서 첫 번째 바이트 사이에 null 바이트가 없는 경우n바이트 수src, 결과는 null로 종료되지 않습니다.

다음과 같이 결백해 보이는 것을 null로 종료하지 않고:

   printf( "FOO: %s\n", dest );

추락할 수도 있어


보다 나은, 안전한 대안이 있는가?strncpy()?

strncpy()더 안전한 곳으로 사용하기 위한 것이 아닙니다.strcpy()는, 1개의 스트링을 다른 스트링의 중간에 삽입하기 위해서 사용됩니다.

다음과 같은 모든 "안전한" 문자열 처리 기능snprintf()그리고.vsnprintf()는 버퍼 오버플로우 악용 등을 완화하기 위해 이후 표준에서 추가된 수정입니다.

위키피디아에서 언급하는 내용strncat()자기 금고를 쓰는 대신strncpy():

*dst = '\0';
strncat(dst, src, LEN);

편집

못 알아 들었어요.strncat()문자열이 LEN 문자보다 길거나 같은 경우 늘 끝내는 경우 LEN 문자를 초과합니다.

어쨌든, 사용의 포인트는strncat()같은 자체 개발 솔루션 대신memcpy(..., strlen(...))/무엇을 실장하는 것이라도strncat()대상/플랫폼이 라이브러리에서 최적화되어 있을 수 있습니다.

물론 dst가 적어도 nullchar를 보유하고 있는지 확인해야 합니다.따라서 dst의 올바른 사용은strncat()예를 들어 다음과 같습니다.

if (LEN) {
    *dst = '\0'; strncat(dst, src, LEN-1);
}

저도 인정합니다strncpy()는 서브스트링을 다른 문자열로 복사하는 데 그다지 유용하지 않습니다.src가 n자보다 짧으면 대상 문자열이 잘립니다.

원래 7th Edition UNIX 파일시스템(DIR(5) 참조)에는 파일명을 14바이트로 제한하는 디렉토리 엔트리가 있었습니다.디렉토리내의 각 엔트리는 inode 번호의 2바이트와 이름의 14바이트로 구성되어 있습니다.다만, 늘 패딩은 14자로 되어 있습니다만, 반드시 null 끝은 아닙니다.제 신념으로는 믿는다strncpy()는, 이러한 디렉토리 구조에서 동작하도록 설계되어 있습니다.또는 적어도 그 구조에서는 완벽하게 동작합니다.

고려사항:

  • 14 문자의 파일명이 null로 종료되지 않았습니다.
  • 이름이 14바이트보다 짧으면 늘 패딩으로 풀렝스(14바이트)가 됩니다.

이는 정확히 다음 방법으로 달성할 수 있습니다.

strncpy(inode->d_name, filename, 14);

so,는,strncpy()본래의 틈새 응용 분야에 이상적으로 적합했습니다.이것은 우연히 null 종단 문자열의 오버플로우를 방지하기 위한 것이었다.

(길이 14까지의 늘 패딩은 심각한 오버헤드가 아닙니다.버퍼의 길이가 4KB이고 버퍼에 20자를 안전하게 복사하기만 하면 추가 4075 늘은 심각한 오버킬이며 긴 버퍼에 재료를 반복적으로 추가할 경우 2차 동작을 일으키기 쉽습니다.)

이미 strlcpy와 같은 안전한 복사를 하는 오픈 소스 구현이 있습니다.

http://en.wikipedia.org/wiki/Strlcpy

참고 자료에는 소스에 대한 링크가 있습니다.

strncpy() , , , , , , , , , , , , , , , , , , , , , , , , , .

snprintf(buffer, BUFFER_SIZE, "%s", src);

한 글이 있습니다.size-1「 」의 문자 .src로로 합니다.dest를 추가합니다.

static inline void cpystr(char *dest, const char *src, size_t size)
{ if(size) while((*dest++ = --size ? *src++ : 0)); }

저는 항상 다음을 선호합니다.

 memset(dest, 0, LEN);
 strncpy(dest, src, LEN - 1);

하지만 그건 그냥 선호도의 문제일 뿐이죠

Strncpy는 프로그램 사용자에 의한 스택 오버플로 공격으로부터 안전합니다.또, Null로 종단하지 않는 문자열을 기술한 대로 인쇄하는 등, 프로그래머가 실행하는 에러로부터 보호하는 것은 아닙니다.

printf에 의해 인쇄되는 문자 수를 제한함으로써 앞에서 설명한 문제의 크래시를 방지할 수 있습니다.

char my_string[10];
//other code here
printf("%.9s",my_string); //limit the number of chars to be printed to 9

새로운 확장에 의존하지 않고, 지금까지 다음과 같은 작업을 실시했습니다.

/* copy N "visible" chars, adding a null in the position just beyond them */
#define MSTRNCPY( dst, src, len) ( strncpy( (dst), (src), (len)), (dst)[ (len) ] = '\0')

그리고 아마도:

/* pull up to size - 1 "visible" characters into a fixed size buffer of known size */
#define MFBCPY( dst, src) MSTRNCPY( (dst), (src), sizeof( dst) - 1)

새로운 내장(?) 기능이 아닌 매크로가 필요한 이유는 무엇입니까?예전에는 C를 매일 실행할 때 포팅해야 하는 다른 비유닉스(비윈도우) 환경뿐만 아니라 여러 Unice가 있었기 때문입니다.

ISO/IEC TR 24731(자세한 내용은 https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/coding/317-BSI.html 참조)에 새로운 대체 방법이 기재되어 있습니다.이러한 함수의 대부분은 타겟 변수의 최대 길이를 지정하는 추가 파라미터를 사용하여 모든 문자열이 늘 종단되며 이름이 로 끝나는 것을 확인합니다._s('안전'의 경우)를 사용하여 이전 '안전'1 버전과 차별화할 수 있습니다.

유감스럽게도 아직 지원을 받고 있으며 특정 도구 세트에서는 사용할 수 없을 수 있습니다.이전 안전하지 않은 기능을 사용하면 Visual Studio의 최신 버전에서 경고가 발생합니다.

사용 중인 툴이 새로운 기능을 지원하지 않는 경우 오래된 기능을 위한 자체 래퍼를 만드는 것은 매우 쉽습니다.다음은 예를 제시하겠습니다.

errCode_t strncpy_safe(char *sDst, size_t lenDst,
                       const char *sSrc, size_t count)
{
    // No NULLs allowed.
    if (sDst == NULL  ||  sSrc == NULL)
        return ERR_INVALID_ARGUMENT;

   // Validate buffer space.
   if (count >= lenDst)
        return ERR_BUFFER_OVERFLOW;

   // Copy and always null-terminate
   memcpy(sDst, sSrc, count);
   *(sDst + count) = '\0';

   return OK;
}

예를 들어, 오버플로우 없이 항상 가능한 한 많은 문자열을 복사하도록 함수를 필요에 맞게 변경할 수 있습니다.VC에서는 VC++에 합격했을 할 수 ._TRUNCATEcount.




1Of course, you still need to be accurate about the size of the target buffer: if you supply a 3-character buffer but tell strcpy_s() it has space for 25 chars, you're still in trouble.

strlcpy(), 여기서 지정 : http://www.courtesan.com/todd/papers/strlcpy.html

libc가 구현되어 있지 않은 경우 다음과 같이 시도해 보십시오.

size_t strlcpy(char* dst, const char* src, size_t bufsize)
{
  size_t srclen =strlen(src);
  size_t result =srclen; /* Result is always the length of the src string */
  if(bufsize>0)
  {
    if(srclen>=bufsize)
       srclen=bufsize-1;
    if(srclen>0)
       memcpy(dst,src,srclen);
    dst[srclen]='\0';
  }
  return result;
}

(2004년에 제가 작성 - 퍼블릭 도메인 전용)

strncpy는 사용 가능한 문자열 버퍼와 직접 연동됩니다.메모리를 직접 조작하고 있는 경우는 버퍼 사이즈가 필요하기 때문에 수동으로 "\0」을 설정할 수 있습니다.

플레인 C에는 이보다 더 좋은 대안이 없다고 생각합니다만, raw memory를 가지고 놀 때는 충분히 주의를 기울이면 그다지 나쁘지 않습니다.

이러한 기능은 설계 이상의 진화를 거듭하고 있기 때문에, 「왜」라고 하는 것은 아닙니다.'어떻게'만 배우면 돼요.유감스럽게도 Linux의 man 페이지에는 이러한 기능의 일반적인 사용 예제가 없습니다.또한 제가 검토한 코드의 오용도 많이 발견되고 있습니다.여기 몇 가지 메모를 해 두었습니다.http://www.pixelbeat.org/programming/gcc/string_buffers.html

언급URL : https://stackoverflow.com/questions/1453876/why-does-strncpy-not-null-terminate

반응형