open 시스템 콜이 SECCOMP에 의해 막혀있다면 openat 시스템 콜을 고려해 볼 수 있다.
-
openat 시스템 콜
#include <fcntl.h>
int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
- open 시스템 콜과 완전히 같게 동작하는데, 다음 부분이 다르다 :
- dirfd 인자는 directory의 fd값으로, pathname이 상대경로라면 상대경로의 기준 위치를 dirfd로 잡는다.
- 만약 pathname이 절대경로라면 dirfd값은 무시된다.
- dirfd값이 AT_FDCWD(-100)이라면 current directory로 설정된다.
-
sendfile 시스템 콜
#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
- in_fd에서 데이터를 읽어와 out_fd에 쓴다.
- 커널 내부에서 모두 이루어지기 때문에 read & write 과정보다 더 효율적이다.
- offset == NULL
- in_fd는 file offset부터 읽기 시작함.
- file offset은 자동으로 업데이트 된다.
- offset != NULL
- file offset값을 가지고 있는 변수를 가리킨다.
- 읽는 시작 위치는 file offset부터 시작되며, sendfile()이 종료되면 offset이 가리키는 변수는 마지막으로 읽은 file의 위치로 설정된다.
- 주의해야 할 점
- sendfile 시스템 콜은 파일 간의 읽고 쓰기를 위한 것이므로, 인자로 들어오는 fd 값들은 모두 파일에 해당하는 것들이어야 한다.
- 만약 파일의 데이터를 stdout에 쓰고 싶다고 해서
sendfile(1, in_fd, NULL, 10);
이런 식으로 쓴다면, 1은 stdout의 fd값이지 파일의 fd값으로 인식하지 않기 때문에 에러가 발생함.
- 그래서 미리
int out_fd = openat(0, "/dev/stdout", O_WRONLY);
를 해 준 후에 이 out_fd를 사용하게 되면 파일로 인식하기 때문에 잘 동작하게 된다.
x주의x
- 파일에 해당하지 않으면 동작하지 않는다는 것은 라이브러리 함수 상에서 그렇다는 것이고, 시스템 콜에서는 그 검증을 하지 않으므로 잘 동작한다.
- 시스템 콜 상에서의 인자의 순서는 함수 호출규약과 다르게, rdi, rsi, rdx, r10, r8, r9 순서이다. 얘 땜에 한참 헤맸네..