FreeBSD Process
Process in FreeBSD
プロセスに関する構造体、struct proc
はsys/proc.h
に定義されている。Linuxでいうtask_struct
みたいな感じ。
proc
の方がシンプルで、task_struct
は定義だけ800行以上あるが、proc
は128行しか無い。
コメントがわかりやすくて助かる。
このproc.h
で面白いのが
extern struct proclist allproc; /* List of all processes. */
で、名前とコメントの通りすべてのプロセスがリストになっている。
リストについては過去の記事を参照
LIST_HEAD(proclist, proc);
proclist
はこうなっている。
see_other_uids
FreeBSDのセキュリティ機構として、see_other_(u|g)ids
がある。
他のユーザのプロセスを参照できなくするというもの
demo
まずは無効になっている状態
[root@freebsd13 ~]# sysctl security.bsd.see_other_uids=1
security.bsd.see_other_uids: 1 -> 1
[root@freebsd13 ~]# sysctl security.bsd.see_other_gids=1
security.bsd.see_other_gids: 1 -> 1
[root@freebsd13 ~]# cat &
[1] 983
見えてる
[vagrant@freebsd13 ~]$ ps aux | grep cat | grep -v grep
root 983 0.0 0.1 12720 2296 2 T 00:45 0:00.00 cat
有効化する
[root@freebsd13 ~]# sysctl security.bsd.see_other_uids=0
security.bsd.see_other_uids: 1 -> 0
[1]+ Stopped cat
[root@freebsd13 ~]# sysctl security.bsd.see_other_gids=0
security.bsd.see_other_gids: 1 -> 0
[root@freebsd13 ~]#
見えなくなる
[vagrant@freebsd13 ~]$ ps aux | grep cat | grep -v grep
[vagrant@freebsd13 ~]$
実装
sys/kern/kern_prot.c
を見ると、
/*
* 'see_other_uids' determines whether or not visibility of processes
* and sockets with credentials holding different real uids is possible
* using a variety of system MIBs.
* XXX: data declarations should be together near the beginning of the file.
*/
static int see_other_uids = 1;
SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
&see_other_uids, 0,
"Unprivileged processes may see subjects/objects with different real uid");
/*-
* Determine if u1 "can see" the subject specified by u2, according to the
* 'see_other_uids' policy.
* Returns: 0 for permitted, ESRCH otherwise
* Locks: none
* References: *u1 and *u2 must not change during the call
* u1 may equal u2, in which case only one reference is required
*/
int
cr_canseeotheruids(struct ucred *u1, struct ucred *u2)
{
if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
if (priv_check_cred(u1, PRIV_SEEOTHERUIDS) != 0)
return (ESRCH);
}
return (0);
}
こんな感じで定義されている。
cr_canseeotheruids
は、同じファイルのcr_cansee
で呼ばれており、
/*-
* Determine if u1 "can see" the subject specified by u2.
* Returns: 0 for permitted, an errno value otherwise
* Locks: none
* References: *u1 and *u2 must not change during the call
* u1 may equal u2, in which case only one reference is required
*/
int
cr_cansee(struct ucred *u1, struct ucred *u2)
{
int error;
if ((error = prison_check(u1, u2)))
return (error);
#ifdef MAC
if ((error = mac_cred_check_visible(u1, u2)))
return (error);
#endif
if ((error = cr_canseeotheruids(u1, u2)))
return (error);
if ((error = cr_canseeothergids(u1, u2)))
return (error);
if ((error = cr_canseejailproc(u1, u2)))
return (error);
return (0);
}
こんな感じで、他の検証も含めて、そのユーザが見れるかどうかをチェックしている。
プロセスについては
/*-
* Determine if td "can see" the subject specified by p.
* Returns: 0 for permitted, an errno value otherwise
* Locks: Sufficient locks to protect p->p_ucred must be held. td really
* should be curthread.
* References: td and p must be valid for the lifetime of the call
*/
int
p_cansee(struct thread *td, struct proc *p)
{
/* Wrap cr_cansee() for all functionality. */
KASSERT(td == curthread, ("%s: td not curthread", __func__));
PROC_LOCK_ASSERT(p, MA_OWNED);
if (td->td_proc == p)
return (0);
return (cr_cansee(td->td_ucred, p->p_ucred));
}
このp_cansee
で検証が行われる。
実際に確認しているところを見る
sys/fs/procfs/procfs_status.c
では
int
procfs_doproccmdline(PFS_FILL_ARGS)
{
/*
* If we are using the ps/cmdline caching, use that. Otherwise
* read argv from the process space.
* Note that if the argv is no longer available, we deliberately
* don't fall back on p->p_comm or return an error: the authentic
* Linux behaviour is to return zero-length in this case.
*/
PROC_LOCK(p);
if (p->p_args && p_cansee(td, p) == 0) {
sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
PROC_UNLOCK(p);
return (0);
}
という感じで、p_cansee
の値を参照している。
BSD、読みやすい。
おわりに
この記事はn01e0 Advent Calendar 2023の19日目の記事です。
また、IPFactory OB Advent Calendar 2023の19日目の記事も兼ねています。
明日はあるかわかりません
Comments