파일 설명자를 강제로 닫는 가장 안전한 방법

파일 설명자를 강제로 닫는 가장 안전한 방법

때로는 파일 시스템을 마운트 해제하거나 루프 장치를 분리해야 하지만 이는 busy열린 파일 설명자 때문이거나 smb서버 프로세스 때문일 수도 있습니다.

강제로 제거하려면 문제가 있는 프로세스를 종료하거나 시도할 수 있지만 kill -SIGTERM이렇게 하면 연결이 닫힙니다 smb(열린 일부 파일이 닫힐 필요가 없더라도).

프로세스가 특정 파일 설명자를 강제로 닫는 영리한 방법을 설명합니다.여기gdb그러나 close(fd)이것은 위험해 보입니다 . 닫힌 설명자가 재활용되면 어떻게 되나요? 프로세스는 이제 완전히 다른 파일을 참조한다는 사실을 인식하지 못한 채 이전 저장소 설명자를 사용하고 있을 수 있습니다.

아이디어가 있지만 어떤 종류의 함정이 있는지 모르겠습니다. 사용하고 gdb열고 /dev/null( O_WRONLY편집: 더 나은 대안으로 제안된 주석 O_PATH) dup2문제의 파일 설명자를 닫고 설명자를 다시 사용합니다 /dev/null. 이렇게 하면 파일 설명자에 대한 읽기 또는 쓰기가 실패합니다.

이와 같이:

sudo gdb -p 234532
(gdb) set $dummy_fd = open("/dev/null", 0x200000) // O_PATH
(gdb) p dup2($dummy_fd, offending_fd)
(gdb) p close($dummy_fd)
(gdb) detach
(gdb) quit

무엇이 잘못될 수 있나요?

답변1

프로세스를 조작하는 것은 거의 안전하지 않지만 gdb긴급 상황이 발생하고 프로세스를 공개 상태로 유지하고 관련된 모든 위험과 코드를 이해해야 하는 경우 필요할 수 있습니다.

대부분의 경우 간단히 프로세스를 종료합니다. 그러나 일부 경우는 환경, 관련 시스템 및 프로세스의 소유자, 프로세스의 수행 작업, "종료 가능"에 대한 사항이 있는지 여부에 따라 달라질 수 있습니다. "아뇨, 누구누구에게 먼저 연락하세요." 등의 문제가 해결되면 이러한 세부 사항은 사후 회의에서 해결해야 할 수도 있습니다. 계획된 마이그레이션이 있는 경우 사전에 확인하는 것이 가장 좋습니다. 열려 있는 프로세스가 있는 경우 긴급하지 않은 상황(마이그레이션 시 이른 아침에만 실행되는 cron 작업 또는 기타 예약된 작업)에서 처리할 수 있도록 문제의 파일 설명자를 지정합니다. 낮에 확인하세요)

쓰기 전용 vs. 읽기 vs. 읽기-쓰기

O_WRONLY모든 파일 설명자가 쓰기 전용이 아니기 때문에 파일 설명자를 다시 여는 아이디어 는 문제가 있습니다. John Viega와 Matt Messier는 "C 및 C++에 대한 보안 프로그래밍 가이드"에서 표준 출력 및 표준 오류와 다르게 표준 입력을 처리하는 보다 미묘한 접근 방식을 취합니다(25페이지, "파일 설명자를 안전하게 관리").

static int open_devnull(int fd) {
  FILE *f = 0;

  if (!fd) f = freopen(_PATH_DEVNULL, "rb", stdin);
  else if (fd == 1) f = freopen(_PATH_DEVNULL, "wb", stdout);
  else if (fd == 2) f = freopen(_PATH_DEVNULL, "wb", stderr);
  return (f && fileno(f) == fd);
}

이 경우 gdb설명자(또는 핸들)가 읽기 전용, 읽기-쓰기 또는 쓰기 전용인지 확인하고 적절한 대체를 활성화해야 합니다. 그렇지 않은 경우 한때 읽기 전용이었던 핸들이 이제 쓰기 전용이 되어 프로세스가 핸들에서 읽으려고 시도하면 불필요한 오류가 발생합니다.FILE */dev/null

어떤 문제가 발생할 수 있나요?

파일 설명자(및 FILE *핸들)가 뒤에서 변조될 때 프로세스가 정확히 어떻게 작동하는지는 프로세스에 달려 있으며 해당 설명자가 "악몽 모드"에서 사용되지 않으면 "아무것도"와 동일합니다. " 은 다르다. 새로 고치지 않은 데이터, 적절한 파일 종료 표시기 없음 또는 기타 예상치 못한 문제로 인해 어딘가의 파일이 손상되었습니다.

핸들의 경우 핸들을 닫기 전에 호출을 추가하면 도움이 될 수도 있고, 이중 버퍼링이나 다른 문제가 발생할 수도 있습니다. 이는 FILE *소스 코드가 무엇을 수행하고 기대하는지 정확히 알지 못한 채fflush(3) 무작위 호출을 수행할 때 발생할 수 있는 몇 가지 위험 중 하나입니다. 소프트웨어는 gdb처리가 필요할 수도 있는 설명자나 핸들 위에 추가적인 복잡성 계층을 구축할 수도 있습니다 . 원숭이 패치 코드는 쉽게 원숭이 렌치로 바뀔 수 있습니다.fdFILE *

일반화하다

프로세스에 표준 종료 신호를 보내면 마치 시스템이 정상적으로 종료된 것처럼 리소스를 적절하게 종료할 수 있는 기회가 주어집니다. 프로세스를 조작하면 gdb상황이 올바르게 종료되지 않을 수 있으며 상황이 더욱 악화될 수 있습니다.

답변2

O_WRONLY를 사용하여 /dev/null을 연 다음 dup2를 사용하여 문제가 있는 파일 설명자를 닫고 해당 설명자를 /dev/null에 재사용합니다. 이렇게 하면 파일 설명자에 대한 읽기 또는 쓰기가 실패합니다.

설명자를 에 복사하면 /dev/null쓰기 작업이 수행되지 않습니다.실패하다, 하지만성공, 그리고 독서는성공그리고 0(eof)을 반환합니다.

이것은 당신이 원하는 것일 수도 있고 아닐 수도 있습니다.

O_WRONLY|O_RDWRLinux에서는 flags=3(일명)을 사용하여 파일을 열 수도 있습니다. O_NOACCESS그러면 읽기 또는 쓰기가 실패하게 됩니다 EBADF.

파일은 ioctl에서만 작동합니다. 이는 다른 답변 및 주석에서 언급되지 않은 위험을 초래합니다. 읽기 및 쓰기는 파일 설명자에서 수행되는 유일한 작업이 아닙니다. ( lseek또는 무엇을 ftruncate?).

고쳐 쓰다:

나는 문서화되지 않은 것보다 더 나은 것을 발견 했습니다 O_WRONLY|O_RDWR. O_PATH = 010000000 / 0x200000open(2) 맨페이지에 따르면:

O_PATH (since Linux 2.6.39)
     Obtain a file descriptor that can be used for two  purposes:  to
     indicate a location in the filesystem tree and to perform opera-
     tions that act purely at the file descriptor  level.   The  file
     itself  is not opened, and other file operations (e.g., read(2),
     write(2), fchmod(2), fchown(2), fgetxattr(2), mmap(2)) fail with
     the error EBADF.

    The  following operations can be performed on the resulting file
     descriptor:

    *  close(2); fchdir(2) (since Linux 3.5); fstat(2) (since  Linux
        3.6).

    *  Duplicating  the  file  descriptor (dup(2), fcntl(2) F_DUPFD,
        etc.).

관련 정보