無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

mountのMS_NOSUID


MS_NOSUIDオプションでmountすると、setuid/setgidが無効になります。MS_NOSUIDオプションでmountシステムコールを呼び出すと、マウントフラグとして MNT_NOSUIDでファイルシステムをマウントします。
long do_mount(char *dev_name, char *dir_name, char *type_page,
                 unsigned long flags, void *data_page)
{

       if (flags & MS_NOSUID)
               mnt_flags |= MNT_NOSUID;
       if (flags & MS_NODEV)
               mnt_flags |= MNT_NODEV;
       if (flags & MS_NOEXEC)
               mnt_flags |= MNT_NOEXEC;
       if (flags & MS_NOATIME)
               mnt_flags |= MNT_NOATIME;
       if (flags & MS_NODIRATIME)
               mnt_flags |= MNT_NODIRATIME;
       if (flags & MS_STRICTATIME)
               mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
       if (flags & MS_RDONLY)
               mnt_flags |= MNT_READONLY;

       flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
                  MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
                  MS_STRICTATIME);

       if (flags & MS_REMOUNT)
               retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
                                   data_page);
       else if (flags & MS_BIND)
               retval = do_loopback(&path, dev_name, flags & MS_REC);
       else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
               retval = do_change_type(&path, flags);
       else if (flags & MS_MOVE)
               retval = do_move_mount(&path, dev_name);
       else
               retval = do_new_mount(&path, type_page, flags, mnt_flags,
                                     dev_name, data_page);
dput_out:
       path_put(&path);
       return retval;
}
ファイルを実行すると、do_exec()からprepare_binprm()がコールされ、bprm->cred->euid = current_euid()/bprm->cred->egid = current_egid()で親プロセスで初期化し、実行しようとしているファイルのファイルシステムのマウントフラグが、MNT_NOSUIDでないなら、bprm->cred->euid = inode->i_uid/bprm->cred->egid = inode->i_gidで更新して、kernel_read()をコールすることになります。
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;

       /* clear any previous set[ug]id data from a previous binary */
       bprm->cred->euid = current_euid();
       bprm->cred->egid = current_egid();

       if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
               /* Set-uid? */
               if (mode & S_ISUID) {
                       bprm->per_clear |= PER_CLEAR_ON_SETID;
                       bprm->cred->euid = inode->i_uid;
               }

               /* Set-gid? */
               if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
                       bprm->per_clear |= PER_CLEAR_ON_SETID;
                       bprm->cred->egid = inode->i_gid;
               }
       }

       /* fill in binprm security blob */
       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);
}
proc_fill_super()は、procfsのスーパブロック取得のコールバック関数です。この時s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXECとしています。procfsではスーパブロックオプションの位置づけで設定されています。従って再マウントする事で、setuid/setgidを有効にできないようになっています。
int proc_fill_super(struct super_block *s)
{
       struct inode * root_inode;

       s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC;
       s->s_blocksize = 1024;
       s->s_blocksize_bits = 10;
       s->s_magic = PROC_SUPER_MAGIC;
       s->s_op = &proc_sops;
       s->s_time_gran = 1;
       
       pde_get(&proc_root);
       root_inode = proc_get_inode(s, &proc_root);
       if (!root_inode)
               goto out_no_root;
       root_inode->i_uid = 0;
       root_inode->i_gid = 0;
       s->s_root = d_alloc_root(root_inode);
       if (!s->s_root)
               goto out_no_root;
       return 0;

out_no_root:
       printk("proc_read_super: get root inode failed\n");
       iput(root_inode);
       pde_put(&proc_root);
       return -ENOMEM;
}


最終更新 2013/12/30 15:47:46 - north
(2013/12/30 15:47:46 作成)