setuid
Rev.1を表示中。最新版はこちら。
ファイルオープン時、rw等のチェックをした後、inode_owner_or_capable()で、current_fsuid() == inode->i_uidとし、ファイル所有者にかかるチェックを行います。current_fsuid()はカレントタスクディスクリプタ下のメンバーcredで、ここに実行uid等の情報が設定されています。
struct task_struct { : const struct cred __rcu *cred; : } struct cred { : uid_t euid; /* effective UID of the task */ gid_t egid; /* effective GID of the task */ uid_t fsuid; /* UID for VFS ops */ gid_t fsgid; /* GID for VFS ops */ : }; bool inode_owner_or_capable(const struct inode *inode) { struct user_namespace *ns = inode_userns(inode); if (current_user_ns() == ns && current_fsuid() == inode->i_uid) return true; if (ns_capable(ns, CAP_FOWNER)) return true; return false; }EXPORT_SYMBOL(inode_owner_or_capable);
inode_init_owner()はinode取得時にコールされ、inodeのuidは取得したカレントプロセスの実行uidが設定されています。
void inode_init_owner(struct inode *inode, const struct inode *dir, umode_t mode) { inode->i_uid = current_fsuid(); if (dir && dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; if (S_ISDIR(mode)) mode |= S_ISGID; } else inode->i_gid = current_fsgid(); inode->i_mode = mode; } EXPORT_SYMBOL(inode_init_owner);プログラムを起動すると言うのは、forkで作成されたプロセスに、ファイルから実行イメージを読み込んで差し替えるということです。その差し替えはdo_exeシステムコールで行うのですが、実行イメージの各種情報をstruct linux_binprm *bprmに設定して、起動ローダの引数として、この*bprmの情報がタスクデュスクリプタに反映されることになります。
setuidの処理は、struct linux_binprm *bprmを設定するprepare_binprm()で行っています。デフォルトでは、カレントの実行uid/gidがstruct linux_binprm *bprmに設定されていますが、実行ファイルにsetuidが設定されていると、タスクデュスクリプタの実行uidは、ファイルのユーザidが設定されるようになっています。
int prepare_binprm(struct linux_binprm *bprm) { umode_t mode; struct inode * inode = bprm->file->f_path.dentry->d_inode; int retval; mode = inode->i_mode; if (bprm->file->f_op == NULL) return -EACCES; bprm->cred->euid = current_euid(); bprm->cred->egid = current_egid(); if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { if (mode & S_ISUID) { bprm->per_clear |= PER_CLEAR_ON_SETID; bprm->cred->euid = inode->i_uid; } if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { bprm->per_clear |= PER_CLEAR_ON_SETID; bprm->cred->egid = inode->i_gid; } } retval = security_bprm_set_creds(bprm); if (retval) return retval; bprm->cred_prepared = 1; memset(bprm->buf, 0, BINPRM_BUF_SIZE); return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); }