diff --git a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml index 78c95b6d66..1f465a8145 100644 --- a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml +++ b/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml @@ -1,685 +1,755 @@ Evan Sarmiento
evms@cs.bu.edu
2001 Evan Sarmiento
The Jail Subsystem security Jail root - On most &unix; systems, root has omnipotent power. This promotes - insecurity. If an attacker were to gain root on a system, he would - have every function at his fingertips. In FreeBSD there are - sysctls which dilute the power of root, in order to minimize the - damage caused by an attacker. Specifically, one of these functions - is called secure levels. Similarly, another function which is - present from FreeBSD 4.0 and onward, is a utility called - &man.jail.8;. Jail chroots an - environment and sets certain restrictions on processes which are - forked from within. For example, a jailed process cannot affect - processes outside of the jail, utilize certain system calls, or - inflict any damage on the main computer. + On most &unix; systems, root has omnipotent power. + This promotes insecurity. If an attacker gained root + on a system, he would have every function at his fingertips. In FreeBSD + there are sysctls which dilute the power of root, in + order to minimize the damage caused by an attacker. Specifically, one of + these functions is called secure levels. Similarly, + another function which is present from FreeBSD 4.0 and onward, is a utility + called &man.jail.8;. Jail chroots an environment + and sets certain restrictions on processes which are forked within + the jail. For example, a jailed process + cannot affect processes outside the jail, + utilize certain system calls, or inflict any damage on the host + environment. Jail is becoming the new security model. People are running potentially vulnerable servers such as - Apache, BIND, and sendmail within jails, so that if an attacker - gains root within the Jail, it is only - an annoyance, and not a devastation. This article focuses on the - internals (source code) of Jail. - It will also suggest improvements upon the jail code base which - are already being worked on. If you are looking for a how-to on - setting up a Jail, I suggest you look - at my other article in Sys Admin Magazine, May 2001, entitled - "Securing FreeBSD using Jail." + Apache, BIND, and + sendmail within jails, so that if an attacker + gains root within the jail, + it is only an annoyance, and not a devastation. This article mainly + focuses on the internals (source code) of jail. + If you are looking for a how-to on setting up a + jail, I suggest you look at my other article + in Sys Admin Magazine, May 2001, entitled "Securing FreeBSD using + Jail." Architecture Jail consists of two realms: the - user-space program, jail, and the code implemented within the - kernel: the jail system call and associated - restrictions. I will be discussing the user-space program and - then how jail is implemented within the kernel. + userland program, &man.jail.8;, and the code implemented within + the kernel: the &man.jail.2; system call and associated + restrictions. I will be discussing the userland program and + then how jail is implemented within + the kernel. - Userland code + Userland Code Jail - userland program + Userland Program - The source for the user-land jail is located in - /usr/src/usr.sbin/jail, consisting of - one file, jail.c. The program takes these - arguments: the path of the jail, hostname, ip address, and the - command to be executed. + The source for the userland jail + is located in /usr/src/usr.sbin/jail, + consisting of one file, jail.c. The program + takes these arguments: the path of the jail, + hostname, IP address, and the command to be executed. Data Structures In jail.c, the first thing I would note is the declaration of an important structure - struct jail j; which was included from + struct jail j; which was included from /usr/include/sys/jail.h. - The definition of the jail structure is: + The definition of the jail structure is: + /usr/include/sys/jail.h: struct jail { u_int32_t version; char *path; char *hostname; u_int32_t ip_number; }; As you can see, there is an entry for each of the - arguments passed to the jail program, and indeed, they are - set during its execution. + arguments passed to the &man.jail.8; program, and indeed, + they are set during its execution. /usr/src/usr.sbin/jail/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]; Networking - One of the arguments passed to the Jail program is an IP - address with which the jail can be accessed over the - network. Jail translates the ip address given into host - byte order and then stores it in j (the jail structure). + One of the arguments passed to the &man.jail.8; program is + an IP address with which the jail + can be accessed over the network. &man.jail.8; translates the + IP address given into host byte order and then stores it in + j (the jail structure). /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); - The - inet_aton - 3 - function "interprets the specified character string as an - Internet address, placing the address into the structure - provided." The ip number node in the jail structure is set - only when the ip address placed onto the in structure by - inet_aton is translated into host byte order by - ntohl(). + The &man.inet.aton.3; function "interprets the specified + character string as an Internet address, placing the address + into the structure provided." The ip_number + member in the jail structure is set only + when the IP address placed onto the in + structure by &man.inet.aton.3; is translated into host byte + order by &man.ntohl.3;. Jailing The Process - Finally, the userland program jails the process, and - executes the command specified. Jail now becomes an - imprisoned process itself and then executes the command - given using &man.execv.3; - - /usr/src/sys/usr.sbin/jail/jail.c + Finally, the userland program jails the process. + Jail now becomes an imprisoned + process itself and then executes the command given using + &man.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]); - As you can see, the jail function is being called, and - its argument is the jail structure which has been filled - with the arguments given to the program. Finally, the - program you specify is executed. I will now discuss how Jail - is implemented within the kernel. + As you can see, the jail() function is + called, and its argument is the jail structure + which has been filled with the arguments given to the program. + Finally, the program you specify is executed. I will now discuss + how jail is implemented within the + kernel. Kernel Space Jail - kernel architecture + Kernel Architecture We will now be looking at the file /usr/src/sys/kern/kern_jail.c. This is - the file where the jail system call, appropriate sysctls, and - networking functions are defined. + the file where the &man.jail.2; system call, appropriate sysctls, + and networking functions are defined. sysctls sysctl In kern_jail.c, the following sysctls are defined: /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"); 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"); + "Processes in jail are limited to creating UNIX/IPv4/route sockets only"); 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"); 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"); 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"); 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"); + "Processes in jail can alter system file flags"); + +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"); Each of these sysctls can be accessed by the user - through the sysctl program. Throughout the kernel, these + through the &man.sysctl.8; program. Throughout the kernel, these specific sysctls are recognized by their name. For example, the name of the first sysctl is security.jail.set_hostname_allowed. &man.jail.2; system call Like all system calls, the &man.jail.2; system call takes two arguments, struct thread *td and struct jail_args *uap. - td is a pointer to the thread + td is a pointer to the thread structure which describes the calling thread. In this - context, uap is a pointer to the structure which specifies the - arguments given to &man.jail.2; from the userland program - jail.c. When I described the userland - program before, you saw that the &man.jail.2; system call was - given a jail structure as its own argument. + context, uap is a pointer to the structure + in which a pointer to the jail structure + passed by the userland jail.c is contained. + When I described the userland program before, you saw that the + &man.jail.2; system call was given a jail + structure as its own argument. /usr/src/sys/kern/kern_jail.c: /* - * MPSAFE - * * struct jail_args { * struct jail *jail; * }; */ int jail(struct thread *td, struct jail_args *uap) - Therefore, uap->jail would access the - jail structure which was passed to the system call. Next, - the system call copies the jail structure into kernel space - using the copyin() - function. copyin() takes three arguments: - the data which is to be copied into kernel space, + Therefore, uap->jail can be used to + access the jail structure which was passed + to the system call. Next, the system call copies the + jail structure into kernel space using + the &man.copyin.9; function. &man.copyin.9; takes three arguments: + the address of the data which is to be copied into kernel space, uap->jail, where to store it, - j and the size of the storage. The jail - structure uap->jail is copied into kernel - space and stored in another jail structure, + j and the size of the storage. The + jail structure pointed by + uap->jail is copied into kernel space and + is stored in another jail structure, j. /usr/src/sys/kern/kern_jail.c: error = copyin(uap->jail, &j, sizeof(j)); There is another important structure defined in - jail.h. It is the prison structure - (pr). The prison structure is used - exclusively within kernel space. The &man.jail.2; system call - copies everything from the jail structure onto the prison - structure. Here is the definition of the prison structure. + jail.h. It is the prison + structure. The prison structure is used + exclusively within kernel space. Here is the definition of the + prison structure. /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; + 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 */ }; - The jail() system call then allocates memory for a - pointer to a prison structure and copies data between the two - structures. + The &man.jail.2; system call then allocates memory for + a prison structure and copies data between + the jail and prison + structure. /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; - These next three lines in the source are very important, - as they specify how the kernel recognizes a process as - jailed. Each process on a &unix; system is described by its - own proc structure. You can see the whole proc structure in - /usr/include/sys/proc.h. For example, - the td argument in any system call is actually a pointer to - that calling thread's thread structure, as stated before. The - td->td_proc is a pointer to the calling process' process - structure. The proc structure contains nodes which can describe - the owner's identity (p_ucred), the process - resource limits (p_limit), and so on. In the - definition of the ucred structure, there is a pointer to a - prison structure. (cr_prison). +if (error) + goto e_dropvnref; +pr->pr_ip = j.ip_number; + Next, we will discuss another important system call + &man.jail.attach.2;, which implements the function to put + a process into the jail. + /usr/src/sys/kern/kern_jail.c: +/* + * struct jail_attach_args { + * int jid; + * }; + */ +int +jail_attach(struct thread *td, struct jail_attach_args *uap) + This system call makes the changes that can distinguish + a jailed process from those unjailed ones. + To understand what &man.jail.attach.2; does for us, certain + background information is needed. + + On FreeBSD, each kernel visible thread is identified by its + thread structure, while the processes are + described by their proc structures. You can + find the definitions of the thread and + proc structure in + /usr/include/sys/proc.h. + For example, the td argument in any system + call is actually a pointer to the calling thread's + thread structure, as stated before. + The td_proc member in the + thread structure pointed by td + is a pointer to the proc structure which + represents the process that contains the thread represented by + td. The proc structure + contains members which can describe the owner's + identity(p_ucred), the process resource + limits(p_limit), and so on. In the + ucred structure pointed by + p_ucred member in the proc + structure, there is a pointer to the prison + structure(cr_prison). /usr/include/sys/proc.h: +struct thread { + ... + struct proc *td_proc; + ... +}; struct proc { -... -struct ucred *p_ucred; -... + ... + struct ucred *p_ucred; + ... }; /usr/include/sys/ucred.h struct ucred { -... -struct prison *cr_prison; -... + ... + struct prison *cr_prison; + ... }; - In kern_jail.c, the function then - calls function jail_attach with a given jid. And the jail_attach - calls function change_root to change the root directory of the - calling process. The jail_attach function then creates a new ucred - structure, and attaches the newly created ucred structure to the - calling process after it has successfully attaches the prison on the - cred structure. From then on, the calling process is recognized as - jailed. When calls function jailed with the newly created ucred - structure as the argument, it returns 1 to tell that the credential - is in a jail. The parent process of each process, forked within - the jail, is the program jail itself, as it calls the &man.jail.2; - system call. When the program is executed through execve, it - inherits the properties of its parent's ucred structure, therefore it - has the jailed ucred structure. + In kern_jail.c, the function + jail() then calls function + jail_attach() with a given jid. + And jail_attach() calls function + change_root() to change the root directory of the + calling process. The jail_attach() then creates + a new ucred structure, and attaches the newly + created ucred structure to the calling process + after it has successfully attached the prison + structure to the ucred structure. From then on, + the calling process is recognized as jailed. When the kernel routine + jailed() is called in the kernel with the newly + created ucred structure as its argument, it + returns 1 to tell that the credential is connected + with a jail. The public ancestor process + of all the process forked within the jail, + is the process which runs &man.jail.8;, as it calls the + &man.jail.2; system call. When a program is executed through + &man.execve.2;, it inherits the jailed property of its parent's + ucred structure, therefore it has a jailed + ucred structure. /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; ... } - When a process is forked from a parent process, the - &man.fork.2; system call uses crhold to maintain the credential - for the newly forked process. It inherently keep the newly forked - child's credential consistent with its parent, so the child process - is also jailed. + When a process is forked from its parent process, the + &man.fork.2; system call uses crhold() to + maintain the credential for the newly forked process. It inherently + keep the newly forked child's credential consistent with its parent, + so the child process is also jailed. /usr/src/sys/kern/kern_fork.c: p2->p_ucred = crhold(td->td_ucred); +... td2->td_ucred = crhold(p2->p_ucred); Restrictions Throughout the kernel there are access restrictions relating - to jailed processes. Usually, these restrictions only check if + to jailed processes. Usually, these restrictions only check whether the process is jailed, and if so, returns an error. For example: - if (jailed(td->td_ucred)) - return (EPERM); + +if (jailed(td->td_ucred)) + return (EPERM); SysV IPC System V IPC System V IPC is based on messages. Processes can send each other these messages which tell them how to act. The functions - which deal with messages are: msgsys, - msgctl, msgget, - msgsend and msgrcv. + which deal with messages are: + &man.msgctl.3;, &man.msgget.3;, &man.msgsnd.3; and &man.msgrcv.3;. Earlier, I mentioned that there were certain sysctls you could - turn on or off in order to affect the behavior of Jail. One of - these sysctls was security.jail.sysvipc_allowed. - On most systems, this sysctl is set to 0. If it were set to 1, - it would defeat the whole purpose of having a jail; privileged - users from within the jail would be able to affect processes - outside of the environment. The difference between a message - and a signal is that the message only consists of the signal - number. + turn on or off in order to affect the behavior of + jail. One of these sysctls was + security.jail.sysvipc_allowed. By default, + this sysctl is set to 0. If it were set to 1, it would defeat the + whole purpose of having a jail; privileged + users from the jail would be able to + affect processes outside the jailed environment. The difference + between a message and a signal is that the message only consists + of the signal number. /usr/src/sys/kern/sysv_msg.c: - &man.msgget.3;: msgget returns (and possibly - creates) a message descriptor that designates a message queue - for use in other system calls. + msgget(key, msgflg): + msgget returns (and possibly creates) a message + descriptor that designates a message queue for use in other + functions. - &man.msgctl.3;: Using this function, a process - can query the status of a message + msgctl(msgid, cmd, buf): + Using this function, a process can query the status of a message descriptor. - &man.msgsnd.3;: msgsnd sends a message to a + msgsnd(msgid, msgp, msgsz, msgflg): + msgsnd sends a message to a process. - &man.msgrcv.3;: a process receives messages using + msgrcv(msgid, msgp, msgsz, msgtyp, + msgflg): a process receives messages using this function - In each of these system calls, there is this - conditional: + In each of the system calls corresponding to these functions, + there is this conditional: /usr/src/sys/kern/sysv_msg.c: -if (!jail_sysvipc_allowed && jailed(td->td_ucred) +if (!jail_sysvipc_allowed && jailed(td->td_ucred)) return (ENOSYS); semaphores Semaphore system calls allow processes to synchronize execution by doing a set of operations atomically on a set of semaphores. Basically semaphores provide another way for processes lock resources. However, process waiting on a semaphore, that is being used, will sleep until the resources are relinquished. The following semaphore system calls are - blocked inside a jail: semsys, - semget, semctl and - semop. + blocked inside a jail: &man.semget.2;, + &man.semctl.2; and &man.semop.2;. /usr/src/sys/kern/sysv_sem.c: - &man.semctl.2;(id, num, cmd, arg): - Semctl does the specified cmd on the semaphore queue - indicated by id. + semctl(semid, semnum, cmd, ...): + semctl does the specified cmd + on the semaphore queue indicated by + semid. - &man.semget.2;(key, nsems, flag): - Semget creates an array of semaphores, corresponding to - key. + semget(key, nsems, flag): + semget creates an array of semaphores, + corresponding to key. - Key and flag take on the same meaning as they + key and flag take on the same meaning as they do in msgget. - &man.semop.2;(semid, sops, nsops): - Semop does the set of semaphore operations in the array of - structures ops, to the set of semaphores identified by - id. + semop(semid, array, nops): + semop performs a group of operations indicated + by array, to the set of semaphores identified by + semid. shared memory System V IPC allows for processes to share memory. Processes can communicate directly with each other by sharing parts of their virtual address space and then reading and writing data stored in the shared memory. These system - calls are blocked within a jailed environment: shmdt, - shmat, oshmctl, shmctl, shmget, and - shmsys. + calls are blocked within a jailed environment: &man.shmdt.2;, + &man.shmat.2;, &man.shmctl.2; and &man.shmget.2;. /usr/src/sys/kern/sysv_shm.c: - &man.shmctl.2;(shmid, cmd, buf): - shmctl does various control operations on the shared memory - region identified by id. - - &man.shmget.2;(key, size, - shmflg): shmget accesses or creates a shared memory - region of size bytes. - - &man.shmat.2;(shmid, shmaddr, shmflg): - shmat attaches a shared memory region identified by id to the - address space of a process. + shmctl(shmid, cmd, buf): + shmctl does various control operations on the + shared memory region identified by + shmid. + + shmget(key, size, flag): + shmget accesses or creates a shared memory + region of size bytes. + + shmat(shmid, addr, flag): + shmat attaches a shared memory region identified + by shmid to the address space of a + process. - &man.shmdt.2;(shmaddr): shmdt - detaches the shared memory region previously attached at - addr. + shmdt(addr): + shmdt detaches the shared memory region + previously attached at addr. Sockets sockets - Jail treats the &man.socket.2; system call and related - lower-level socket functions in a special manner. In order to - determine whether a certain socket is allowed to be created, - it first checks to see if the sysctl + Jail treats the &man.socket.2; system + call and related lower-level socket functions in a special manner. + In order to determine whether a certain socket is allowed to be + created, it first checks to see if the sysctl security.jail.socket_unixiproute_only is set. If set, sockets are only allowed to be created if the family specified is either PF_LOCAL, PF_INET or PF_ROUTE. Otherwise, it returns an error. /usr/src/sys/kern/uipc_socket.c: int -socreate(dom, aso, type, proto, cred, td) -... +socreate(int dom, struct socket **aso, int type, int proto, + struct ucred *cred, struct thread *td) { struct protosw *prp; ... if (jailed(cred) && jail_socket_unixiproute_only && prp->pr_domain->dom_family != PF_LOCAL && prp->pr_domain->dom_family != PF_INET && prp->pr_domain->dom_family != PF_ROUTE) { return (EPROTONOSUPPORT); } ... } Berkeley Packet Filter Berkeley Packet Filter data link layer - The Berkeley Packet Filter provides a raw interface to - data link layers in a protocol independent fashion. The - function bpfopen() opens an Ethernet - device. It's now controlled by the devfs whether can be used - in the jail. + The Berkeley Packet Filter provides + a raw interface to data link layers in a protocol independent + fashion. BPF is now controlled by the + &man.devfs.8; whether it can be used in a jailed environment. Protocols protocols There are certain protocols which are very common, such as TCP, UDP, IP and ICMP. IP and ICMP are on the same level: the network layer 2. There are certain precautions which are taken in order to prevent a jailed process from binding a - protocol to a certain port only if the nam - parameter is set. nam is a pointer to a sockaddr structure, + protocol to a certain address only if the nam + parameter is set. nam is a pointer to a + sockaddr structure, which describes the address on which to bind the service. A - more exact definition is that sockaddr "may be used as a - template for referring to the identifying tag and length of - each address"[2]. In the function - in_pcbbind_setup, sin is a - pointer to a sockaddr_in structure, which contains the port, - address, length and domain family of the socket which is to be - bound. Basically, this disallows any processes from jail to be - able to specify the domain family. + more exact definition is that sockaddr "may be + used as a template for referring to the identifying tag and length of + each address". In the function + in_pcbbind_setup(), sin is a + pointer to a sockaddr_in structure, which + contains the port, address, length and domain family of the socket + which is to be bound. Basically, this disallows any processes from + jail to be able to specify the address + that doesn't belong to the jail in which + the calling process exists. /usr/src/sys/netinet/in_pcb.c: int in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, u_short *lportp, struct ucred *cred) { ... struct sockaddr_in *sin; ... if (nam) { sin = (struct sockaddr_in *)nam; ... -#ifdef notdef - /* - * We should check the family, but old programs - * incorrectly fail to initialize it. - */ - if (sin->sin_family != AF_INET) - return (EAFNOSUPPORT); -#endif if (sin->sin_addr.s_addr != INADDR_ANY) if (prison_ip(cred, 0, &sin->sin_addr.s_addr)) return(EINVAL); ... + if (lport) { + ... + if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr)) + return (EADDRNOTAVAIL); + ... + } + } + if (lport == 0) { + ... + if (laddr.s_addr != INADDR_ANY) + if (prison_ip(cred, 0, &laddr.s_addr)) + return (EINVAL); + ... } +... + if (prison_ip(cred, 0, &laddr.s_addr)) + return (EINVAL); ... } You might be wondering what function - prison_ip() does. prison_ip is given three - arguments, a pointer to the credential(represented by - cred), any flags, and an ip address. It - returns 1 if the ip address does NOT belong to the jail or - 0 otherwise. As you can see from the code, if it is indeed - an ip address not belonging to the jail, the protcol is - not allowed to bind to a certain port. + prison_ip() does. prison_ip() + is given three arguments, a pointer to the credential(represented by + cred), any flags, and an IP address. It + returns 1 if the IP address does NOT belong to the + jail or 0 otherwise. As you can see + from the code, if it is indeed an IP address not belonging to the + jail, the protcol is not allowed to bind + to that address. /usr/src/sys/kern/kern_jail.c: int prison_ip(struct ucred *cred, int flag, u_int32_t *ip) { u_int32_t tmp; if (!jailed(cred)) return (0); if (flag) tmp = *ip; else tmp = ntohl(*ip); if (tmp == INADDR_ANY) { if (flag) *ip = cred->cr_prison->pr_ip; else *ip = htonl(cred->cr_prison->pr_ip); return (0); } if (tmp == INADDR_LOOPBACK) { if (flag) *ip = cred->cr_prison->pr_ip; else *ip = htonl(cred->cr_prison->pr_ip); return (0); } if (cred->cr_prison->pr_ip != tmp) return (1); return (0); } - - Jailed users are not allowed to bind services to an ip - which does not belong to the jail. The restriction is also - written within the function in_pcbbind_setup: - - /usr/src/sys/netinet/in_pcb.c - if (nam) { - ... - lport = sin->sin.port; - ... if (lport) { - ... - if (jailed(cred)) - prison = 1; - ... - if (prison && - prison_ip(cred, 0, &sin->sin_addr.s_addr)) - return (EADDRNOTAVAIL); - Filesystem filesystem - Even root users within the jail are not allowed to set any - file flags, such as immutable, append, and no unlink flags, if - the securelevel is greater than 0. + Even root users within the + jail are not allowed to unset or modify + any file flags, such as immutable, append-only, and undeleteable + flags, if the securelevel is greater than 0. - /usr/src/sys/ufs/ufs/ufs_vnops.c: + /usr/src/sys/ufs/ufs/ufs_vnops.c: static int ufs_setattr(ap) ... { ... - if (!suser_cred(cred, - jail_chflags_allowed ? SUSER_ALLOWJAIL : 0)) { + if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) { if (ip->i_flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { - error = securelevel_gt(cred, 0); - if (error) - return (error); + error = securelevel_gt(cred, 0); + if (error) + return (error); } ... + } +} +/usr/src/sys/kern/kern_priv.c +int +priv_check_cred(struct ucred *cred, int priv, int flags) +{ + ... + error = prison_priv_check(cred, priv); + if (error) + return (error); + ... +} +/usr/src/sys/kern/kern_jail.c +int +prison_priv_check(struct ucred *cred, int priv) +{ + ... + switch (priv) { + ... + case PRIV_VFS_SYSFLAGS: + if (jail_chflags_allowed) + return (0); + else + return (EPERM); + ... + } + ... } -