procのhidepidオプション
/procをlsすると、動作している全プロセスpidでディレクトリが作成されますが、procfsをマウントする時、hidepid=1でマウントすると、プロセスIDは表示されますが、カレントPID以外は参照できません。hidepid=2でマウントすると他のpidのディレクトリそのものが表示されません。デフォルトはオプション0でマウントされています。
has_perms==FALSEと言うことは、hidepidは0のパーミッションを有していない。と言うことで、結果的にパーミッションを有しているということです。(まどろっこしい実装してます。)
で、pid->hide_pid == 1ならEPERM、pid->hide_pid == 2ならENOENTと言うことです。
proc_fs_typeのmountコールバック関数proc_mount()から、proc_parse_options()がコールされ、gid/hidepidオプションの設定を行います。
[kitamura@localhost proc]$ ls -l | sort -k 3 合計 0 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1151 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1152 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1153 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1154 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1155 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1156 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1157 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1158 dr-xr-xr-x 8 avahi avahi 0 7月 24 03:48 843 dr-xr-xr-x 8 avahi avahi 0 7月 24 03:48 865 dr-xr-xr-x 8 dbus dbus 0 7月 24 03:48 866 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 03:48 1405 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 04:03 2012 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 04:03 2013 dr-xr-xr-x 8 mysql mysql 0 7月 24 03:48 1139 dr-xr-xr-x 8 mysql mysql 0 7月 24 03:48 965 dr-xr-xr-x 8 root root 0 7月 24 01:54 1 -r-------- 1 root root 0 7月 24 01:54 kmsg -r--r--r-- 1 root root 0 7月 24 01:54 swaps dr-xr-xr-x 1 root root 0 7月 24 01:54 sys dr-xr-xr-x 8 root root 0 7月 24 03:48 10 dr-xr-xr-x 8 root root 0 7月 24 03:48 11 : :リンク先は参照できませんが、1151ホルダ(apache)等は参照できます。
[kitamura@localhost proc]$ ls 1151/ ls: シンボリックリンク 1151/cwd を読み込めません: 許可がありません ls: シンボリックリンク 1151/root を読み込めません: 許可がありません ls: シンボリックリンク 1151/exe を読み込めません: 許可がありません attr cmdline environ latency mountinfo oom_adj root stack task autogroup comm exe limits mounts oom_score sched stat wchan auxv coredump_filter fd loginuid mountstats oom_score_adj schedstat statm cgroup cpuset fdinfo maps net pagemap sessionid status clear_refs cwd io mem ns personality smaps syscallhidepid=1でマウントすると、1151ホルダ(apache)等は表示されますが、その中は参照できません。
[root@localhost ~]# mount /proc -o remount,hidepid=1 [kitamura@localhost proc]$ ls -l | sort -k 3 合計 0 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1151 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1152 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1153 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1154 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1155 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1156 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1157 dr-xr-xr-x 8 apache apache 0 7月 24 03:48 1158 dr-xr-xr-x 8 avahi avahi 0 7月 24 03:48 843 dr-xr-xr-x 8 avahi avahi 0 7月 24 03:48 865 dr-xr-xr-x 8 dbus dbus 0 7月 24 03:48 866 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 03:48 1405 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 04:03 2012 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 04:03 2013 dr-xr-xr-x 8 mysql mysql 0 7月 24 03:48 1139 dr-xr-xr-x 8 mysql mysql 0 7月 24 03:48 965 dr-xr-xr-x 8 root root 0 7月 24 01:54 1 -r-------- 1 root root 0 7月 24 01:54 kmsg -r--r--r-- 1 root root 0 7月 24 01:54 swaps dr-xr-xr-x 1 root root 0 7月 24 01:54 sys dr-xr-xr-x 8 root root 0 7月 24 03:48 10 dr-xr-xr-x 8 root root 0 7月 24 03:48 11 : : [kitamura@localhost proc]$ ls 1151/ ls: ディレクトリ 1151/ を開くことが出来ません: 許可されていない操作ですhidepid=2でマウントすると、proc下のkitamura以外のプロセスファイル自身が表示されません。
[root@localhost ~]# mount /proc -o remount,hidepid=2 [kitamura@localhost proc]$ ls -l | sort -k 3 合計 0 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 04:07 1405 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 04:07 2040 dr-xr-xr-x 8 kitamura kitamura 0 7月 24 04:07 2041 -r-------- 1 root root 0 7月 24 01:54 kmsg -r--r--r-- 1 root root 0 7月 24 01:54 swaps dr-xr-xr-x 1 root root 0 7月 24 01:54 sys dr-xr-xr-x 2 root root 0 7月 24 04:07 acpi dr-xr-xr-x 5 root root 0 7月 24 04:07 asoundprocfsのinode_operationsの.permissionコールバック関数proc_pid_permission()は、ディレクトリ参照コールされ、hidepidのチェックが行われます。has_pid_permissions()は第三引数の1より小さいパーミッションを有しているかどうのかチェックを行います。従って1より小さいと言うことで、hidepidが0のパーミッションを有しているかどうかのチェックとなります。
has_perms==FALSEと言うことは、hidepidは0のパーミッションを有していない。と言うことで、結果的にパーミッションを有しているということです。(まどろっこしい実装してます。)
で、pid->hide_pid == 1ならEPERM、pid->hide_pid == 2ならENOENTと言うことです。
#define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ static int proc_pid_permission(struct inode *inode, int mask) { struct pid_namespace *pid = inode->i_sb->s_fs_info; struct task_struct *task; bool has_perms; task = get_proc_task(inode); if (!task) return -ESRCH; has_perms = has_pid_permissions(pid, task, 1); put_task_struct(task); if (!has_perms) { if (pid->hide_pid == 2) { return -ENOENT; } return -EPERM; } return generic_permission(inode, mask); }file_operationsの.readdirコールバック関数のproc_pid_readdir()でprocfsディレクトリを取得します。最初のforループでproc_base_stuff[]のディレクトリをとりあえずfilldirに取得し、if (has_pid_permissions(ns, iter.task, 2))でhidepidが0,1の時は、ディレクトリをdirentに設定しています。
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) { unsigned int nr; struct task_struct *reaper; struct tgid_iter iter; struct pid_namespace *ns; filldir_t __filldir; if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET) goto out_no_task; nr = filp->f_pos - FIRST_PROCESS_ENTRY; reaper = get_proc_task(filp->f_path.dentry->d_inode); if (!reaper) goto out_no_task; for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) { const struct pid_entry *p = &proc_base_stuff[nr]; if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0) goto out; } ns = filp->f_dentry->d_sb->s_fs_info; iter.task = NULL; iter.tgid = filp->f_pos - TGID_OFFSET; for (iter = next_tgid(ns, iter); iter.task; iter.tgid += 1, iter = next_tgid(ns, iter)) { if (has_pid_permissions(ns, iter.task, 2)) __filldir = filldir; else __filldir = fake_filldir; filp->f_pos = iter.tgid + TGID_OFFSET; if (proc_pid_fill_cache(filp, dirent, __filldir, iter) < 0) { put_task_struct(iter.task); goto out; } } filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; out: put_task_struct(reaper); out_no_task: return 0; }has_pid_permissions()でpid->hide_pidがhide_pid_minより小さい場合、その権限までのペーミッションを有していると言うことです。もし有していないならpid->pid_gidにかかるチェック等を行った結果を返します。
static bool has_pid_permissions(struct pid_namespace *pid, struct task_struct *task, int hide_pid_min) { if (pid->hide_pid < hide_pid_min) return true; if (in_group_p(pid->pid_gid)) return true; return ptrace_may_access(task, PTRACE_MODE_READ); }
proc_fs_typeのmountコールバック関数proc_mount()から、proc_parse_options()がコールされ、gid/hidepidオプションの設定を行います。
static struct file_system_type proc_fs_type = { .name = "proc", .mount = proc_mount, .kill_sb = proc_kill_sb, }; static const match_table_t tokens = { {Opt_hidepid, "hidepid=%u"}, {Opt_gid, "gid=%u"}, {Opt_err, NULL}, }; static int proc_parse_options(char *options, struct pid_namespace *pid) { char *p; substring_t args[MAX_OPT_ARGS]; int option; if (!options) return 1; while ((p = strsep(&options, ",")) != NULL) { int token; if (!*p) continue; args[0].to = args[0].from = 0; token = match_token(p, tokens, args); switch (token) { case Opt_gid: if (match_int(&args[0], &option)) return 0; pid->pid_gid = option; break; case Opt_hidepid: if (match_int(&args[0], &option)) return 0; if (option < 0 || option > 2) { pr_err("proc: hidepid value must be between 0 and 2.\n"); return 0; } pid->hide_pid = option; break; default: pr_err("proc: unrecognized mount option \"%s\" " "or missing value\n", p); return 0; } } return 1; }