¡¡¡¡ÔÚ´ó¶àÊý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¡·¡£
¡¡¡¡JailÓÉÁ½²¿·Ö×é³É£ºÓû§¼¶³ÌÐò£¬ Ò²¾ÍÊÇjail(8)£»»¹ÓÐÔÚÄÚºËÖÐJailµÄʵÏÖ´úÂ룺jail(2) ϵͳµ÷ÓúÍÏà¹ØµÄÔ¼Êø¡£ÎÒ½«ÌÖÂÛÓû§¼¶³ÌÐòºÍjailÔÚÄÚºËÖеÄʵÏÖÔÀí¡£
¡¡¡¡JailµÄÓû§¼¶Ô´´úÂëÔÚ/usr/src/usr.sbin/jail£¬ ÓÉÒ»¸öÎļþjail.c×é³É¡£Õâ¸ö³ÌÐòÓÐÕâЩ²ÎÊý£ºjailµÄ·¾¶£¬ Ö÷»úÃû£¬IPµØÖ·£¬»¹ÓÐÐèÒªÖ´ÐеÄÃüÁî¡£
¡¡¡¡ÔÚ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];
¡¡¡¡´«¸ø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³ÉÔ±¡£
¡¡¡¡×îºó£¬Óû§¼¶³ÌÐòÇô½û½ø³Ì¡£ÏÖÔÚ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ÔÚÄÚºËÖеÄʵÏÖ¡£
¡¡¡¡ÏÖÔÚÎÒÃÇÀ´¿´Îļþ/usr/src/sys/kern/kern_jail.c¡£ ÔÚÕâÀﶨÒåÁËjail(2)µÄϵͳµ÷Óá¢Ïà¹ØµÄ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¡£
¡¡¡¡ÏñËùÓеÄϵͳµ÷ÓÃÒ»Ñù£¬ÏµÍ³µ÷ÓÃ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>.