O_CLOEXEC
Rev.3を表示中。最新版はこちら。
ファイルモードがO_CLOEXECなら、exec(外部コマンド)によるプロセスでは、そのファイルを参照する事はできません。
[root@localhost c]# cat closeexec1.c
#include <stdio.h>
#include <fcntl.h>
void main(int argc, char* argv[])
{
int pfd1[2], pfd2[2];
pipe2(pfd1, 0);
dup3(pfd1[0], 253, 0);
pipe2(pfd2, 0);
dup3(pfd2[0], 254, O_CLOEXEC);
write(pfd1[1], "01234", 5);
write(pfd2[1], "56789", 5);
system("./closeexec2.o");
}
[root@localhost c]# cat closeexec2.c
#include <stdio.h>
#include <string.h>
void main(int argc, char* argv[])
{
int ret;
char buff[6];
printf("read from NO_O_CLOEXEC\n");
memset(buff, 0, 6);
ret = read(253,buff, 5);
printf("%2d:%s\n", ret, buff);
printf("read from O_CLOEXEC\n");
memset(buff, 0, 6);
ret = read(254,buff, 5);
printf("%2d:%s\n", ret, buff);
}
[root@localhost c]# ./closeexec1.o read from NO_O_CLOEXEC 5:01234 read from O_CLOEXEC -1:alloc_fd()でcurrent->file[file ID] = struct file *file;としファイルIDを取得します。flagsがO_CLOEXECなら、そのファイルIDをcurrent->files->fdt->close_on_execのビット位置として設定され、forkで継承した子プロセスのclose_on_execのビット位置の掛かるファイルをexecでcloseされます。
#define FD_SET(fd,fdsetp) __FD_SET(fd,fdsetp)
int alloc_fd(unsigned start, unsigned flags)
{
struct files_struct *files = current->files;
unsigned int fd;
int error;
struct fdtable *fdt;
spin_lock(&files->file_lock);
repeat:
fdt = files_fdtable(files);
fd = start;
if (fd < files->next_fd)
fd = files->next_fd;
if (fd < fdt->max_fds)
fd = find_next_zero_bit(fdt->open_fds->fds_bits,
fdt->max_fds, fd);
error = expand_files(files, fd);
if (error < 0)
goto out;
if (error)
goto repeat;
if (start <= files->next_fd)
files->next_fd = fd + 1;
FD_SET(fd, fdt->open_fds);
if (flags & O_CLOEXEC)
FD_SET(fd, fdt->close_on_exec);
else
FD_CLR(fd, fdt->close_on_exec);
error = fd;
#if 1
if (rcu_dereference_raw(fdt->fd[fd]) != NULL) {
printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);
rcu_assign_pointer(fdt->fd[fd], NULL);
}
#endif
out:
spin_unlock(&files->file_lock);
return error;
}
O_CLOEXECできるファイルIDの最大は1024で、longサイズが4バイト時fds_bits[32]です。
#define __NFDBITS (8 * sizeof(unsigned long))
#define __FD_SETSIZE 1024
#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS)
typedef struct {
unsigned long fds_bits [__FDSET_LONGS];
} __kernel_fd_set;
static inline void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
{
unsigned long __tmp = __fd / __NFDBITS;
unsigned long __rem = __fd % __NFDBITS;
__fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
}
execはsearch_binary_handler()でコマンドファイルのファイルシステムのstruct linux_binfmtを取得し、load_elf_binaryコールバックでコマンドイメージをロードします。この時、flush_old_files()でfdt->close_on_exec->fds_bits[]毎のセットされているビット位置をファイルIDとするファイルをクローズします。
static void flush_old_files(struct files_struct * files)
{
long j = -1;
struct fdtable *fdt;
spin_lock(&files->file_lock);
for (;;) {
unsigned long set, i;
j++;
i = j * __NFDBITS;
fdt = files_fdtable(files);
if (i >= fdt->max_fds)
break;
set = fdt->close_on_exec->fds_bits[j];
if (!set)
continue;
fdt->close_on_exec->fds_bits[j] = 0;
spin_unlock(&files->file_lock);
for ( ; set ; i++,set >>= 1) {
if (set & 1) {
sys_close(i);
}
}
spin_lock(&files->file_lock);
}
spin_unlock(&files->file_lock);
}






