예상되는 결과는 예측할 수없는 결과입니다. sendfile()
은 원자가 아니므로 파일 설명자에서 read()
을 호출하고 소켓 설명자에서 write()
을 호출하는 자체 루프를 작성하는 것과 실질적으로 동일합니다. 이 과정에서 파일에 다른 프로세스가 쓰면 이전 내용과 새로운 내용이 혼합되어 나타납니다. 주로 여러 편의 시스템 호출을 필요로하지 않으며 응용 프로그램 버퍼간에 앞뒤로 복사하는 대신 파일 버퍼와 소켓 버퍼간에 직접 복사 할 수 있으므로 훨씬 더 효율적이어야하지만 주로 편의 기능으로 생각하십시오. 이 때문에 취약성 창은 read/write
루프를 수행하는 것보다 작아야하지만 여전히 존재합니다.
이 문제를 방지하려면 쓰기를 수행하는 프로세스와 sendfile()
을 호출하는 프로세스 사이에서 파일 잠금을 사용해야합니다.
lock the file
call sendfile()
unlock the file
와 쓰기 과정을 수행해야합니다 : 그래서 순서가 있어야한다
이
lock the file
write to the file
unlock the file
편집 : 그것은이 간단한처럼 사실
, 그것은 보인다, sendfile()
링크 소켓 때문에 버퍼를 커널에 복사하는 대신 파일 버퍼 캐시에 저장하십시오. sendfile()
은 데이터가 전송 될 때까지 기다리지 않으므로 파일을 반환 한 후에 수정하면 전송 된 데이터에 영향을 줄 수 있습니다. 응용 프로그램 계층 승인을 통해 데이터가 모두 수신되었는지 확인해야합니다. 이러한 세부 사항을 설명하는 기사에서 발췌 한 내용은 Minimizing copies when writing large data to a socket을 참조하십시오.
열려있는 파일을 지우더라도 커널의 파일 핸들 (그리고 프로세스의'fd')은 닫힐 때까지 파일을 "활성"상태로 유지합니다. 이것은 또한'fd' 핸들에 영향을 미치지 않고 열린 파일을 "옮길"수있는 이유이기도합니다. 편집으로 인한 경쟁 조건에 대해서는 ... 잘, 그것은 인종입니다. sendfile이 편집 후에 작동하면 편집 된 버전에서 작동합니다. – Myst
쓰기는 실행중인 프로그램, OS 및 심지어 HD 컨트롤러에 의해 버퍼링 될 수 있습니다. 세 명 모두 연속으로. 가장 좋은 방법은 다중 스레드 프로그램에서 동일한 파일을 읽고 쓸 때 원자 가드를 추가하는 것입니다. – usr2564301
@ usr2564301 HD 컨트롤러는 응용 프로그램과 관련이 없습니다. Linux에는 통합 버퍼 캐시가 있으며 모든 프로세스는 동일한 커널 파일 버퍼를 사용합니다. – Barmar