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;
}






