ファイル参照チェック
chdir/open等のファイル参照時、do_inode_permission()で、inodeのpermissionから、参照内容に応じたチェックが行われます。
inodeオペレーションコールバックの.permissionが定義されていなければ、generic_permission()がコールされます。sysfs/procfs等では.permissionは定義されてますが、ext等のファイルシステムでは、定義されていません。
inode->i_opflags |= IOP_FASTPERMは、二回目以降のdo_inode_permission()コール時、inodeキャッシュのpermissionコールバックがNULLかのチェックでなく、inode->i_opflagsをビット演算によるチェックでの効率化故かと思いますが、他の箇所でIOP_FASTPERMを使用されておらず、permission()その物の負荷を考慮すると、意味の無い効率化かと思います。
inode_userns(inode)は、inodeの属するnamespaceで、プロセスnamespaceに関係なく、作成されるinodeは、root_userプロセスのnamespaceに属する事になります。ns_capable()は、カレントプロセスが指定されるケーパビリティを有しているかチェックします。
ディレクトリの時、inode/ACLの参照条件に関係なく、ケーパビリティがCAP_DAC_OVERRIDEなら読書き(ls/rm/)OK。CAP_DAC_READ_SEARCHなら読込み(ls)OKです。
ファイルでは、CAP_DAC_OVERRIDEなら読書き可能。実行でU/G/OのどれかがOKなら実行可能となります。(userチェックでuserのEXEがセットされてなく、otherのEXEがセットされているなら、実行できるという事です。)
CAP_DAC_READ_SEARCHなら、読込みのみOKです。
rootは、これ等のケーパビリティは設定されており、inode->i_modeで読み書き不可としても、読み書きできるのは、ケーパビリティ所以です。
current->cred->fsuidがinode->i_uid(ファイルを作成したユーザID)なら、User(mode >>= 6)でチェックします。
それ以外、ACLのチェックをし、in_group_p()で、setgroupsシステムコールで設定されるcred->group_info->blocks[]のプロセスが属するグループにinode->i_gidを有しているなら、Group(mode >>= 3)でチェックします。
inodeオペレーションコールバックの.permissionが定義されていなければ、generic_permission()がコールされます。sysfs/procfs等では.permissionは定義されてますが、ext等のファイルシステムでは、定義されていません。
inode->i_opflags |= IOP_FASTPERMは、二回目以降のdo_inode_permission()コール時、inodeキャッシュのpermissionコールバックがNULLかのチェックでなく、inode->i_opflagsをビット演算によるチェックでの効率化故かと思いますが、他の箇所でIOP_FASTPERMを使用されておらず、permission()その物の負荷を考慮すると、意味の無い効率化かと思います。
static inline int do_inode_permission(struct inode *inode, int mask)
{
if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
if (likely(inode->i_op->permission))
return inode->i_op->permission(inode, mask);
spin_lock(&inode->i_lock);
inode->i_opflags |= IOP_FASTPERM;
spin_unlock(&inode->i_lock);
}
return generic_permission(inode, mask);
}
acl_permission_check()でinode->i_modeおよびACLに掛かる参照チェックを行い、参照不可ならケーパビリティに掛かる参照チェックを行います。inode_userns(inode)は、inodeの属するnamespaceで、プロセスnamespaceに関係なく、作成されるinodeは、root_userプロセスのnamespaceに属する事になります。ns_capable()は、カレントプロセスが指定されるケーパビリティを有しているかチェックします。
ディレクトリの時、inode/ACLの参照条件に関係なく、ケーパビリティがCAP_DAC_OVERRIDEなら読書き(ls/rm/)OK。CAP_DAC_READ_SEARCHなら読込み(ls)OKです。
ファイルでは、CAP_DAC_OVERRIDEなら読書き可能。実行でU/G/OのどれかがOKなら実行可能となります。(userチェックでuserのEXEがセットされてなく、otherのEXEがセットされているなら、実行できるという事です。)
CAP_DAC_READ_SEARCHなら、読込みのみOKです。
rootは、これ等のケーパビリティは設定されており、inode->i_modeで読み書き不可としても、読み書きできるのは、ケーパビリティ所以です。
int generic_permission(struct inode *inode, int mask)
{
int ret;
ret = acl_permission_check(inode, mask);
if (ret != -EACCES)
return ret;
if (S_ISDIR(inode->i_mode)) {
if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
return 0;
if (!(mask & MAY_WRITE))
if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
return 0;
return -EACCES;
}
if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO))
if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
return 0;
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
if (mask == MAY_READ)
if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
return 0;
return -EACCES;
}
inode->i_modeは、上位9ビットから3ビット単位で、u/g/oです。プロセスのnamespaceは、新規にnamespaceを設定しないかぎり、初期プロセスのそれを継承します。プロセスnamespaceがinodeのネームスペース(初期プロセスのnamespace)と異なる時、Other(mode >>= 0)でチェックします。current->cred->fsuidがinode->i_uid(ファイルを作成したユーザID)なら、User(mode >>= 6)でチェックします。
それ以外、ACLのチェックをし、in_group_p()で、setgroupsシステムコールで設定されるcred->group_info->blocks[]のプロセスが属するグループにinode->i_gidを有しているなら、Group(mode >>= 3)でチェックします。
#define MAY_EXEC 0x00000001
#define MAY_WRITE 0x00000002
#define MAY_READ 0x00000004
static int acl_permission_check(struct inode *inode, int mask)
{
unsigned int mode = inode->i_mode;
if (current_user_ns() != inode_userns(inode))
goto other_perms;
if (likely(current_fsuid() == inode->i_uid))
mode >>= 6;
else {
if (IS_POSIXACL(inode) && (mode & S_IRWXG)) {
int error = check_acl(inode, mask);
if (error != -EAGAIN)
return error;
}
if (in_group_p(inode->i_gid))
mode >>= 3;
}
other_perms:
if ((mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
return 0;
return -EACCES;
}
#define inode_userns(inode) (&init_user_ns)
#define current_user_ns() (current_cred_xxx(user_ns))
#define current_cred_xxx(xxx) \
({ \
current_cred()->xxx; \
})
#define current_cred() \
rcu_dereference_protected(current->cred, 1)
struct user_namespace init_user_ns = {
.kref = {
.refcount = ATOMIC_INIT(3),
},
.creator = &root_user,
};






