µÚ4Õ ¡¡Jail×Óϵͳ

Ŀ¼
4.1 JailµÄϵͳ½á¹¹
4.2 ϵͳ¶Ô±»Çô½û³ÌÐòµÄÏÞÖÆ
Evan Sarmiento°æÈ¨ © 2001 Evan Sarmiento·­Ò룺intron@intron.ac.

¡¡¡¡ÔÚ´ó¶àÊýUNIX®ÏµÍ³ÖУ¬Óû§rootÊÇÍòÄܵġ£ÕâÒ²¾ÍÔö¼ÓÁËÐí¶àΣÏÕ¡£ Èç¹ûÒ»¸ö¹¥»÷Õß»ñµÃÁËÒ»¸öϵͳÖеÄroot£¬¾Í¿ÉÒÔÔÚËûµÄÖ¸¼âÕÆÎÕϵͳÖÐËùÓеŦÄÜ¡£ ÔÚFreeBSDÀÓÐһЩsysctlÏîÏ÷ÈõÁËrootµÄȨÏÞ£¬ ÕâÑù¾Í¿ÉÒÔ½«¹¥»÷ÕßÔì³ÉµÄË𺦼õСµ½×îµÍÏÞ¶È¡£ÕâЩ°²È«¹¦ÄÜÖУ¬ÓÐÒ»Öֽа²È«¼¶±ð¡£ ÁíÒ»ÖÖÔÚFreeBSD 4.0¼°ÒÔºó°æ±¾ÖÐÌṩµÄ°²È«¹¦ÄÜ£¬¾ÍÊÇjail(8)¡£ Jail½«Ò»¸öÔËÐл·¾³µÄÎļþÊ÷¸ùÇл»µ½Ä³Ò»Ìض¨Î»Ö㬠²¢ÇÒ¶ÔÕâÑù»·¾³Öвæ·ÖÉú³ÉµÄ½ø³Ì×ö³öÏÞÖÆ¡£ÀýÈ磬 Ò»¸ö±»¼à½ûµÄ½ø³Ì²»ÄÜÓ°ÏìÕâ¸öjailÖ®ÍâµÄ½ø³Ì¡¢²»ÄÜʹÓÃÒ»Ð©ÌØ¶¨µÄϵͳµ÷Ó㬠Ҳ¾Í²»ÄܶÔÖ÷¼ÆËã»úÔì³ÉÆÆ»µ¡£

ÒëÕß×¢: Ó¢Îĵ¥´Ê¡°jail¡±µÄÖÐÎÄÒâ˼ÊÇ¡°Çô½û¡¢¼à½û¡±¡£

¡¡¡¡JailÒѾ­³ÉΪһÖÖÐÂÐ͵ݲȫģÐÍ¡£ ÈËÃÇ¿ÉÒÔÔÚjailÖÐÔËÐи÷ÖÖ¿ÉÄܴܺàÈõµÄ·þÎñÆ÷³ÌÐò£¬ÈçApache¡¢ BINDºÍsendmail¡£ ÕâÑùÒ»À´£¬¼´Ê¹Óй¥»÷ÕßÈ¡µÃÁËjailÖеÄroot£¬ Õâ×î¶àÈÃÈËÃÇÖåÖåüͷ£¬¶ø²»»áʹÈËÃǾª»Åʧ´ë¡£ ±¾ÎÄÖ÷Òª¹Ø×¢jailµÄÄÚ²¿Ô­Àí(Ô´´úÂë)¡£ Èç¹ûÄãÕýÔÚѰÕÒÉèÖÃJailµÄÖ¸ÄÏÐÔÎĵµ£¬ ÎÒ½¨ÒéÄãÔĶÁÎÒµÄÁíһƪÎÄÕ£¬·¢±íÔÚSys Admin Magazine, May 2001, ¡¶Securing FreeBSD using Jail¡·¡£

4.1 JailµÄϵͳ½á¹¹

¡¡¡¡JailÓÉÁ½²¿·Ö×é³É£ºÓû§¼¶³ÌÐò£¬ Ò²¾ÍÊÇjail(8)£»»¹ÓÐÔÚÄÚºËÖÐJailµÄʵÏÖ´úÂ룺jail(2) ϵͳµ÷ÓúÍÏà¹ØµÄÔ¼Êø¡£ÎÒ½«ÌÖÂÛÓû§¼¶³ÌÐòºÍjailÔÚÄÚºËÖеÄʵÏÖÔ­Àí¡£

4.1.1 Óû§¼¶´úÂë

¡¡¡¡JailµÄÓû§¼¶Ô´´úÂëÔÚ/usr/src/usr.sbin/jail£¬ ÓÉÒ»¸öÎļþjail.c×é³É¡£Õâ¸ö³ÌÐòÓÐÕâЩ²ÎÊý£ºjailµÄ·¾¶£¬ Ö÷»úÃû£¬IPµØÖ·£¬»¹ÓÐÐèÒªÖ´ÐеÄÃüÁî¡£

4.1.1.1 Êý¾Ý½á¹¹

¡¡¡¡ÔÚjail.cÖУ¬ÎÒ½«×îÏÈ×¢½âµÄÊÇÒ»¸öÖØÒª½á¹¹Ìå struct jail j;µÄÉùÃ÷£¬Õâ¸ö½á¹¹ÀàÐ͵ÄÉùÃ÷°üº¬ÔÚ /usr/include/sys/jail.hÖ®ÖС£

¡¡¡¡jail½á¹¹µÄ¶¨ÒåÊÇ£º

/usr/include/sys/jail.h: 

struct jail {
        u_int32_t       version;
        char            *path;
        char            *hostname;
        u_int32_t       ip_number;
};

¡¡¡¡ÕýÈçÄãËù¼û£¬´«Ë͸øÃüÁîjail(8)µÄÿ¸ö²ÎÊý¶¼ÔÚÕâÀïÓжÔÓ¦µÄÒ»Ïî¡£ ÊÂʵÉÏ£¬µ±ÃüÁîjail(8)±»Ö´ÐÐʱ£¬ÕâЩ²ÎÊý²ÅÓÉÃüÁîÐÐÕæÕý´«È룺

/usr/src/usr.sbin/jail.c
char path[PATH_MAX];
...
if(realpath(argv[0], path) == NULL)
    err(1, "realpath: %s", argv[0]);
if (chdir(path) != 0)
    err(1, "chdir: %s", path);
memset(&j, 0, sizeof(j));
j.version = 0; 
j.path = path;
j.hostname = argv[1];

4.1.1.2 ÍøÂç

¡¡¡¡´«¸øjail(8)µÄ²ÎÊýÖÐÓÐÒ»¸öÊÇIPµØÖ·¡£ÕâÊÇÔÚÍøÂçÉÏ·ÃÎÊjailʱµÄµØÖ·¡£ jail(8)½«IPµØÖ··­Òë³ÉÍøÂç×Ö½Ú˳Ðò£¬²¢´æÈëj(jailÀàÐ͵ĽṹÌå)¡£

/usr/src/usr.sbin/jail/jail.c:
struct in_addr in; 
... 
if (inet_aton(argv[2], &in) == 0)
    errx(1, "Could not make sense of ip-number: %s", argv[2]);
j.ip_number = ntohl(in.s_addr);

¡¡¡¡º¯Êýinet_aton(3)¡°½«Ö¸¶¨µÄ×Ö·û´®½âÊÍΪһ¸öInternetµØÖ·£¬ ²¢½«Æäת´æµ½Ö¸¶¨µÄ½á¹¹ÌåÖС±¡£inet_aton(3)É趨Á˽ṹÌåin£¬ Ö®ºóinÖеÄÄÚÈÝÔÙÓÃntohl(3)ת»»³ÉÖ÷»ú×Ö½Ú˳Ðò£¬ ²¢ÖÃÈëjail½á¹¹ÌåµÄip_number³ÉÔ±¡£

4.1.1.3 Çô½û½ø³Ì

¡¡¡¡×îºó£¬Óû§¼¶³ÌÐòÇô½û½ø³Ì¡£ÏÖÔÚJail×ÔÉí±ä³ÉÁËÒ»¸ö±»Çô½ûµÄ½ø³Ì£¬ ²¢Ê¹ÓÃexecv(3)Ö´ÐÐÓû§Ö¸¶¨µÄÃüÁî¡£

/usr/src/usr.sbin/jail/jail.c
i = jail(&j); 
...
if (execv(argv[3], argv + 3) != 0)
    err(1, "execv: %s", argv[3]);

¡¡¡¡ÕýÈçÄãËù¼û£¬º¯Êýjail()±»µ÷Ó㬲ÎÊýÊǽṹÌåjailÖб»ÌîÈëÊý¾ÝÏ ¶øÈçǰËùÊö£¬ÕâЩÊý¾ÝÏîÓÖÀ´×Ôjail(8)µÄÃüÁîÐвÎÊý¡£ ×îºó£¬Ö´ÐÐÁËÓû§Ö¸¶¨µÄÃüÁî¡£ÏÂÃæÎÒ½«¿ªÊ¼ÌÖÂÛjailÔÚÄÚºËÖеÄʵÏÖ¡£

4.1.2 Ïà¹ØµÄÄÚºËÔ´´úÂë

¡¡¡¡ÏÖÔÚÎÒÃÇÀ´¿´Îļþ/usr/src/sys/kern/kern_jail.c¡£ ÔÚÕâÀﶨÒåÁËjail(2)µÄϵͳµ÷Óá¢Ïà¹ØµÄsysctlÏ»¹ÓÐÍøÂ纯Êý¡£

4.1.2.1 sysctlÏî

¡¡¡¡ÔÚkern_jail.cÀﶨÒåÁËÈçÏÂsysctlÏî:

/usr/src/sys/kern/kern_jail.c:

int     jail_set_hostname_allowed = 1;
SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
    &jail_set_hostname_allowed, 0,
    "Processes in jail can set their hostnames");
    /* JailÖеĽø³Ì¿ÉÉ趨×ÔÉíµÄÖ÷»úÃû */

int     jail_socket_unixiproute_only = 1;
SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
    &jail_socket_unixiproute_only, 0,
    "Processes in jail are limited to creating UNIX/IPv4/route sockets only");
    /* JailÖеĽø³Ì±»ÏÞÖÆÖ»Äܽ¨Á¢UNIXÌ×½Ó×Ö¡¢IPv4Ì×½Ó×Ö¡¢Â·ÓÉÌ×½Ó×Ö */

int     jail_sysvipc_allowed = 0;
SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
    &jail_sysvipc_allowed, 0,
    "Processes in jail can use System V IPC primitives");
    /* JailÖеĽø³Ì¿ÉÒÔʹÓÃSystem V½ø³Ì¼äͨѶԭÓï */

static int jail_enforce_statfs = 2;
SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW,
    &jail_enforce_statfs, 0,
    "Processes in jail cannot see all mounted file systems");
    /* jail ÖеĽø³Ì²é¿´ÏµÍ³ÖйҽӵÄÎļþϵͳʱÊܵ½ºÎÖÖÏÞÖÆ */

int    jail_allow_raw_sockets = 0;
SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW,
    &jail_allow_raw_sockets, 0,
    "Prison root can create raw sockets");
    /* jail ÖÐµÄ root Óû§ÊÇ·ñ¿ÉÒÔ´´½¨ raw socket */

int    jail_chflags_allowed = 0;
SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW,
    &jail_chflags_allowed, 0,
    "Processes in jail can alter system file flags");
    /* jail ÖеĽø³ÌÊÇ·ñ¿ÉÒÔÐÞ¸Äϵͳ¼¶Îļþ±ê¼Ç */

int     jail_mount_allowed = 0;
SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW,
    &jail_mount_allowed, 0,
    "Processes in jail can mount/unmount jail-friendly file systems");
    /* jail ÖеĽø³ÌÊÇ·ñ¿ÉÒÔ¹ÒÔØ»òÐ¶ÔØ¶ÔjailÓѺõÄÎļþϵͳ */

¡¡¡¡ÕâЩsysctlÏîÖеÄÿһ¸ö¶¼¿ÉÒÔÓÃÃüÁîsysctl(8)·ÃÎÊ¡£ÔÚÕû¸öÄÚºËÖУ¬ ÕâЩsysctlÏî°´Ãû³Æ±êʶ¡£ÀýÈ磬ÉÏÊöµÚÒ»¸ösysctlÏîµÄÃû×ÖÊÇ security.jail.set_hostname_allowed¡£

4.1.2.2 jail(2)ϵͳµ÷ÓÃ

¡¡¡¡ÏñËùÓеÄϵͳµ÷ÓÃÒ»Ñù£¬ÏµÍ³µ÷ÓÃjail(2)´øÓÐÁ½¸ö²ÎÊý£¬ struct thread *tdºÍstruct jail_args *uap¡£ tdÊÇÒ»¸öÖ¸Ïòthread½á¹¹ÌåµÄÖ¸Õ룬¸ÃÖ¸ÕëÓÃÓÚÃèÊöµ÷ÓÃjail(2)µÄÏ̡߳£ ÔÚÕâ¸öÉÏÏÂÎÄÖУ¬uapÖ¸ÏòÒ»¸ö½á¹¹Ì壬Õâ¸ö½á¹¹ÌåÖаüº¬ÁËÒ»¸öÖ¸Ïò´ÓÓû§¼¶ jail.c´«Ë͹ýÀ´µÄjail½á¹¹ÌåµÄÖ¸Õë¡£ ÔÚÇ°ÃæÎÒ½²ÊöÓû§¼¶³ÌÐòʱ£¬ÄãÒѾ­¿´µ½¹ýÒ»¸öjail½á¹¹Ìå±»×÷Ϊ²ÎÊý´«Ë͸øÏµÍ³µ÷Óà jail(2)¡£

/usr/src/sys/kern/kern_jail.c:
/*
 * struct jail_args {
 *      struct jail *jail;
 * };
 */
int
jail(struct thread *td, struct jail_args *uap)

¡¡¡¡ÓÚÊÇuap->jail¿ÉÒÔÓÃÓÚ·ÃÎʱ»´«µÝ¸øjail(2)µÄjail½á¹¹Ìå¡£ È»ºó£¬jail(2)ʹÓÃcopyin(9)½«jail½á¹¹Ì叴֯µ½ÄÚºËÄÚ´æ¿Õ¼äÖС£ copyin(9)ÐèÒªÈý¸ö²ÎÊý£ºÒª¸´ÖƽøÄÚºËÄÚ´æ¿Õ¼äµÄÊý¾ÝµÄµØÖ· uap->jail£¬ÔÚÄÚºËÄÚ´æ¿Õ¼ä´æ·ÅÊý¾ÝµÄj£¬ ÒÔ¼°Êý¾ÝµÄ´óС¡£uap->jailÖ¸ÏòµÄJail½á¹¹Ìå±»¸´ÖƽøÄÚºËÄÚ´æ¿Õ¼ä£¬ ²¢±»´æ·ÅÔÚÁíÒ»¸öjail½á¹¹ÌåjÀï¡£

/usr/src/sys/kern/kern_jail.c: 
error = copyin(uap->jail, &j, sizeof(j));

¡¡¡¡ÔÚjail.hÖж¨ÒåÁËÁíÒ»¸öÖØÒªµÄ½á¹¹ÌåÐÍprison¡£ ½á¹¹ÌåprisonÖ»±»ÓÃÔÚÄں˿ռäÖС£ ÏÂÃæÊÇprison½á¹¹ÌåµÄ¶¨Òå¡£

/usr/include/sys/jail.h:
struct prison {
        LIST_ENTRY(prison) pr_list;                     /* (a) all prisons */
        int              pr_id;                         /* (c) prison id */
        int              pr_ref;                        /* (p) refcount */
        char             pr_path[MAXPATHLEN];           /* (c) chroot path */
        struct vnode    *pr_root;                       /* (c) vnode to rdir */
        char             pr_host[MAXHOSTNAMELEN];       /* (p) jail hostname */
        u_int32_t        pr_ip;                         /* (c) ip addr host */
        void            *pr_linux;                      /* (p) linux abi */
        int              pr_securelevel;                /* (p) securelevel */
        struct task      pr_task;                       /* (d) destroy task */
        struct mtx       pr_mtx;
        void            **pr_slots;                     /* (p) additional data */
};

¡¡¡¡È»ºó£¬ÏµÍ³µ÷ÓÃjail(2)Ϊһ¸öprison½á¹¹Ìå·ÖÅäÒ»¿éÄڴ棬 ²¢ÔÚjailºÍprison½á¹¹ÌåÖ®¼ä¸´ÖÆÊý¾Ý¡£

/usr/src/sys/kern/kern_jail.c:
MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
...
error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0);
if (error)
    goto e_killmtx;
...
error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
if (error)
        goto e_dropvnref;
pr->pr_ip = j.ip_number;

¡¡¡¡ÏÂÃæ£¬ÎÒÃǽ«ÌÖÂÛÁíÍâÒ»¸öÖØÒªµÄϵͳµ÷ÓÃjail_attach(2)£¬ËüʵÏÖÁ˽«½ø³Ì¼à½ûµÄ¹¦ÄÜ¡£

/usr/src/sys/kern/kern_jail.c
/*
 * struct jail_attach_args {
 *      int jid;
 * };
 */
int
jail_attach(struct thread *td, struct jail_attach_args *uap)

¡¡¡¡Õâ¸öϵͳµ÷ÓÃ×ö³öһЩ¿ÉÒÔÓÃÓÚÇø·Ö±»¼à½ûºÍδ±»¼à½ûµÄ½ø³ÌµÄ¸Ä±ä¡£ ÒªÀí½âjail_attach(2)ΪÎÒÃÇ×öÁËʲô£¬ÎÒÃÇÊ×ÏÈÒªÀí½âһЩ±³¾°ÐÅÏ¢¡£

¡¡¡¡ÔÚFreeBSDÖУ¬Ã¿¸ö¶ÔÄں˿ɼûµÄÏß³ÌÊÇͨ¹ýÆäthread½á¹¹ÌåÀ´Ê¶±ðµÄ£¬ ͬʱ£¬½ø³Ì¶¼ÓÉËüÃÇ×Ô¼ºµÄproc½á¹¹ÌåÃèÊö¡£ Äã¿ÉÒÔÔÚ/usr/include/sys/proc.hÖÐÕÒµ½threadºÍproc½á¹¹ÌåµÄ¶¨Òå¡£ ÀýÈ磬ÔÚÈκÎϵͳµ÷ÓÃÖУ¬²ÎÊýtdʵ¼ÊÉÏÊǸöÖ¸Ïòµ÷ÓÃÏ̵߳Äthread½á¹¹ÌåµÄÖ¸Õ룬 ÕýÈçÇ°ÃæËù˵µÄÄÇÑù¡£tdËùÖ¸ÏòµÄthread½á¹¹ÌåÖеÄtd_proc³ÉÔ±ÊÇÒ»¸öÖ¸Õ룬 Õâ¸öÖ¸ÕëÖ¸ÏòtdËù±íʾµÄÏß³ÌËùÊô½ø³ÌµÄproc½á¹¹Ìå¡£ ½á¹¹Ìåproc°üº¬µÄ³ÉÔ±¿ÉÒÔÃèÊöËùÓÐÕßµÄÉí·Ý (p_ucred)£¬½ø³Ì×ÊÔ´ÏÞÖÆ(p_limit)£¬ µÈµÈ¡£ÔÚÓÉproc½á¹¹ÌåµÄp_ucred³ÉÔ±ËùÖ¸ÏòµÄucred½á¹¹ÌåµÄ¶¨ÒåÖУ¬ »¹ÓÐÒ»¸öÖ¸Ïòprison½á¹¹ÌåµÄÖ¸Õë(cr_prison)¡£

/usr/include/sys/proc.h: 
struct thread {
    ...
    struct proc *td_proc;
    ...
};
struct proc {
    ...
    struct ucred *p_ucred;
    ...
};
/usr/include/sys/ucred.h
struct ucred {
    ...
    struct prison *cr_prison;
    ...
};

¡¡¡¡ÔÚkern_jail.cÖУ¬º¯Êýjail()ÒÔ¸ø¶¨µÄjid µ÷Óú¯Êýjail_attach()¡£Ëæºójail_attach()µ÷Óú¯Êýchange_root()ÒÔ¸Ä±ä µ÷Óýø³ÌµÄ¸ùĿ¼¡£½ÓÏÂÀ´£¬jail_attach()´´½¨Ò»¸öеÄucred½á¹¹Ì壬²¢ÔÚ ³É¹¦µØ½«prison½á¹¹ÌåÁ¬½Óµ½Õâ¸öucred½á¹¹Ìåºó£¬½«Õâ¸öucred½á¹¹ÌåÁ¬½Ó µ½µ÷Óýø³ÌÉÏ¡£´Ó´ËʱÆð£¬Õâ¸öµ÷Óýø³Ì¾Í»á±»Ê¶±ðΪ±»¼à½ûµÄ¡£ µ±ÎÒÃÇÒÔд´½¨µÄÕâ¸öucred½á¹¹ÌåΪ²ÎÊýµ÷ÓÃÄں˷¾¶jailed()ʱ£¬ Ëü½«·µ»Ø1À´ËµÃ÷Õâ¸öÓû§Éí·ÝÊǺÍÒ»¸öjailÏàÁ¬µÄ¡£ ÔÚjailÖвæ·Ö³öÀ´µÄËùÓнø³ÌµÄµÄ¹«¹²×æÏȽø³Ì¾ÍÊÇÕâ¸öÖ´ÐÐÁËjail(2)µÄ½ø³Ì£¬ ÒòΪÕýÊÇËüµ÷ÓÃÁËjail(2)ϵͳµ÷Óᣵ±Ò»¸ö³ÌÐòͨ¹ýexecve(2)¶ø±»Ö´ÐÐʱ£¬ Ëü½«´ÓÆä¸¸½ø³ÌµÄucred½á¹¹Ìå¼Ì³Ð±»¼à½ûµÄÊôÐÔ£¬ Òò¶øËüÒ²»áÓµÓÐÒ»¸ö±»¼à½ûµÄucred½á¹¹Ìå¡£

/usr/src/sys/kern/kern_jail.c
int
jail(struct thread *td, struct jail_args *uap)
{
...
    struct jail_attach_args jaa;
...
    error = jail_attach(td, &jaa);
    if (error)
        goto e_dropprref;
...
}
  
int
jail_attach(struct thread *td, struct jail_attach_args *uap)
{
    struct proc *p;
    struct ucred *newcred, *oldcred;
    struct prison *pr;
...
    p = td->td_proc;
...
    pr = prison_find(uap->jid);
...
    change_root(pr->pr_root, td);
...
    newcred->cr_prison = pr;
    p->p_ucred = newcred;
...
}

¡¡¡¡µ±Ò»¸ö½ø³Ì±»´ÓÆä¸¸½ø³Ì²æ·ÖÀ´µÄʱºò£¬ ϵͳµ÷ÓÃfork(2)½«ÓÃcrhold()À´Î¬»¤ÆäÉí·Ýƾ֤¡£ ÕâÑù£¬ºÜ×ÔÈ»µÄ¾Í±£³ÖÁË×Ó½ø³ÌµÄÉí·Ýƾ֤ÓÚÆä¸¸½ø³ÌÒ»Ö£¬ËùÒÔ×Ó½ø³ÌÒ²ÊDZ»¼à½ûµÄ¡£

/usr/src/sys/kern/kern_fork.c:
p2->p_ucred = crhold(td->td_ucred);
...
td2->td_ucred = crhold(p2->p_ucred);

±¾ÎĵµºÍÆäËüÎĵµ¿É´ÓÕâÀïÏÂÔØ£ºftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

Èç¹û¶ÔÓÚFreeBSDÓÐÎÊÌ⣬ÇëÏÈÔĶÁÎĵµ£¬Èç²»Äܽâ¾öÔÙÁªÏµ<questions@FreeBSD.org>.
¹ØÓÚ±¾ÎĵµµÄÎÊÌâÇë·¢ÐÅÁªÏµ <doc@FreeBSD.org>.