Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Aug 2001 21:23:22 -0400
From:      Evan Sarmiento <ems@open-root.org>
To:        freebsd-hackers@freebsd.org
Subject:   Re: kern/29423: [PATCH] kernel security hooks implementation
Message-ID:  <15211.20106.216833.788917@smtp.sekt7.org>
In-Reply-To: <200108040120.f741K0w36931@freefall.freebsd.org>
References:  <200108040115.f741FnO36727@freefall.freebsd.org> <200108040120.f741K0w36931@freefall.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Hey,

Just wanted to send a message to hackers about my project, to find any suggestions, etc. You
can access the actual PR at http://www.freebsd.org/cgi/query-pr.cgi?pr=29423

Description:
Kernel Security Hooks provide a standard interface for programmers of kernel security
extensions to intercept system calls and other functions. Before, programmers had to wrap
the system call with their own system call, resulting in two copyins. PRFW, the kernel
security hook patch I am addressing in this PR, provides a standard interface for these
uses. It also provides per-pid restrictions, so process X might not be able to use setuid
but process Y might, depending on what restrictions you write.

        I have also written a brief howto at http://www.sekt7.org/~ems/prfw.howto
        You can also download the patch at http://www.sekt7.org/~ems/patch

        Quick installation: cd /usr/src && patch -p < patch

        I'm pretty much a kernel newbie, but this is certanly a large achievement for me,
to code all this, so take pity, I'm sure my code has problems, but I've tested it and
it has worked beautifully.

        Note: this only works on i386 platform due to a change to i386/i386/trap.c
Thanks,
- Evan S

System:
5.0-CURRENT

Patch:
diff -c -r --new-file /usr/src/sys/sys/jailuser.h src/sys/sys/jailuser.h
*** /usr/src/sys/sys/jailuser.h	Wed Dec 31 19:00:00 1969
--- src/sys/sys/jailuser.h	Fri Aug  3 16:25:51 2001
***************
*** 0 ****
--- 1,97 ----
+ /*
+  * Copyright (c) 2001 Evan M. Sarmiento
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modifcation, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must maintain the above copyright
+  *    notice, this list of conditions and the following disclaimer:
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE. EVEN IF ADVISED OF THE POSSIBILITY OF
+  * SUCH DAMAGE.
+  *
+  */
+ 
+ #ifndef _SYS_JAUSR_H_
+ #define _SYS_JAUSR_H_
+ 
+ #include <sys/queue.h>
+ #include <sys/syscall.h>
+ #include <sys/types.h>
+ 
+ 
+ 
+ struct prfw_usr {
+  pid_t pid;  
+  int pr_securelevel;
+ };
+ 
+ #ifndef _KERNEL
+ int   prfw_printstat               __P((pid_t *, char *, struct prfw_usr *));
+ 
+ #else 
+ 
+ #ifdef MALLOC_DECLARE
+ MALLOC_DECLARE(M_USRJAIL);
+ MALLOC_DECLARE(M_PRFW);
+ #endif
+ 
+ #define ALL     1
+ #define ALLBR   2
+ #define ALLPR   3
+ #define prfw_sl p->p_ucred->cr_prfw->pr_securelevel
+ 
+ #define IS_PRFW p->p_ucred->cr_prfw
+ #define IS_RES(x) (x)->p_ucred->cr_prfw
+  
+ #define prfw_operation(sl, synum) (p->p_ucred->cr_prfw->prfw_syscall_ind[synum]->operations[sl])(p, uap)
+ #define prfw_operation_a(sl, synum) (p->p_ucred->cr_prfw->prfw_syscall_ind[synum]->operations[sl])(p, args)
+ #define prfw_operation_p(sl, synum, p) ((p)->p_ucred->cr_prfw->prfw_syscall_ind[synum]->operations[sl])(p, NULL)
+ #define prfw_operation_all(sl, synum, rrp) ((rrp)->prfw_syscall_ind[synum]->operations[sl])(p, args)
+ 
+ struct prfw_krn {
+   pid_t pr_uid;
+   int   pr_securelevel;
+   struct prfw_syscall_r *prfw_syscall_ind[SYS_MAXSYSCALL];
+ };
+ 
+ struct prfw_all_res {
+   int ex_root;
+   int sl;
+   struct prfw_syscall_r *prfw_syscall_ind[SYS_MAXSYSCALL];
+ };
+ 
+ struct prfw_syscall_r {
+   int       num;
+   int       (*operations[3])(p, uap);
+ 
+ };
+ 
+ 
+ 
+ int   prfw_setflags                __P((int , pid_t, int));
+ int   prfw_inject_fp               __P((int , int, pid_t , int (*fp)(p, uap)));
+ int   prfw_sy_initres              __P((struct prfw_syscall_r *sy_index[]));
+ int   prfw_default_handler         __P((struct proc *, void* uap));
+ pid_t prfw_chproc                  __P((struct proc *));
+ struct prfw_all_res * prfw_ret_all __P((void));
+ int   prfw_free                    __P((pid_t, struct prfw_all_res *, int));
+ #endif /* !_KERNEL */
+ #endif /* !_SYS_JAUSR_H_ */
+ 
+ 
+ 
+ 
diff -c -r --new-file /usr/src/sys/sys/ucred.h src/sys/sys/ucred.h
*** /usr/src/sys/sys/ucred.h	Fri May 25 12:59:10 2001
--- src/sys/sys/ucred.h	Fri Aug  3 16:26:00 2001
***************
*** 59,64 ****
--- 59,65 ----
  	struct	uidinfo *cr_uidinfo;	/* per euid resource consumption */
  	struct	uidinfo *cr_ruidinfo;	/* per ruid resource consumption */
  	struct	prison *cr_prison;	/* jail(4) */
+ 	struct  prfw_krn *cr_prfw;
  	struct	mtx cr_mtx;		/* protect refcount */
  };
  #define cr_gid cr_groups[0]
diff -c -r --new-file /usr/src/sys/kern/kern_jailuser.c src/sys/kern/kern_jailuser.c
*** /usr/src/sys/kern/kern_jailuser.c	Wed Dec 31 19:00:00 1969
--- src/sys/kern/kern_jailuser.c	Fri Aug  3 15:29:45 2001
***************
*** 0 ****
--- 1,323 ----
+ 
+ /*
+  * Copyright (c) 2001 Evan M. Sarmiento
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without  
+  * modifcation, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must maintain the above copyright
+  *    notice, this list of conditions and the following disclaimer:
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
+  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+  * OUT OF THE USE OF THIS SOFTWARE. EVEN IF ADVISED OF THE POSSIBILITY OF 
+  * SUCH DAMAGE.  
+  *
+  */
+ 
+ #include <sys/param.h>
+ #include <sys/lock.h>
+ #include <sys/mutex.h>
+ #include <sys/types.h>
+ #include <sys/kernel.h>
+ #include <sys/sysent.h>
+ #include <sys/systm.h>
+ #include <sys/errno.h>
+ #include <sys/sysproto.h>
+ #include <sys/malloc.h>
+ #include <sys/proc.h>
+ #include <sys/queue.h>
+ #include <sys/syscall.h>
+ #include <sys/jailuser.h>
+ 
+ 
+ /* Init routines. */
+ MALLOC_DEFINE(M_PRFW, "process fw", "fw struct");
+ 
+ int prfw_queue_status;
+ int prfw_all_status;
+ struct prfw_all_res *prfw_allproc;
+ 
+ /* prfw_setflags(p, uap)
+    Copies info to struct prfw_tbcp, then inserts it into a list.
+    when processes are forked(), executed(), or preform functions
+     they check against that list
+    */
+ int
+ prfw_setflags(sl, pid, flags)
+ 	int sl;
+ 	pid_t pid;
+ 	int flags;
+ {
+ 
+   int error;
+   int x;
+   pid_t id;
+   int p_pri;
+ 
+   
+   struct prfw_krn       *prfw_tbcp;                   /* to be copied into proc or list */
+   struct prfw_krn       *prfw_acc;                   /* prfw_acc for checking if already exists in list */
+   struct prfw_syscall_r *prfw_syscall_ind[SYS_MAXSYSCALL];
+   struct proc           *nproc;                 /* used to check if process exists */
+     
+ 
+   p_pri = splvm();
+   printf("prfw: Processor priority raised to %d \n", p_pri);
+   
+       
+   id = pid;  
+   
+   if (id != NULL)
+     {
+   if((nproc = pfind(id)) == NULL)
+     return (0);
+     }  
+  		 
+     
+   printf("prfw: Found PID %d. Copied PID's proc structure into nproc.\n", id);
+     
+     
+   if (!sl)
+     return (-2);
+   
+   
+     /* Allocating prfw_tbcp */
+   MALLOC(prfw_tbcp, struct prfw_krn *, sizeof *prfw_tbcp, M_PRFW, M_WAITOK|M_ZERO);
+   
+   /* Malloc loop for allocating an array of pointers in prfw_syscall_ind
+      for restrictions */
+   
+   for (x = 0; x < SYS_MAXSYSCALL; x++)
+     MALLOC(prfw_syscall_ind[x], struct prfw_syscall_r *, sizeof *prfw_syscall_ind * SYS_MAXSYSCALL, M_PRFW, M_WAITOK|M_ZERO);
+   printf("prfw: prfw_syscall_ind array, which is an array of pointers to prfw_syscall_r structures was malloc'd sucessfully. \n");
+ 
+ 
+   prfw_sy_initres(prfw_syscall_ind); 
+   
+   printf("prfw: prfw_sy_initres finished sucessfully, initalizing function pointers to default_handler \n");
+   
+   if (flags)
+     {
+       if (!prfw_all_status)
+ 	{
+       printf("prfw: allproc specified, mallocing \n");
+       MALLOC(prfw_allproc, struct prfw_all_res *, sizeof *prfw_allproc, M_PRFW, M_WAITOK|M_ZERO);
+       prfw_all_status = 1;
+       prfw_allproc->sl = sl;
+       printf("prfw: Set prfw_allproc->sl \n");
+       
+         }
+       if (flags == ALLBR)
+       {
+ 	printf("prfw: setting exclude root bit \n");
+ 	prfw_allproc->ex_root = 1;
+       }
+ 	printf("prfw: inserting prfw_syscall_ind into allproc \n");
+ 	for (x = 0; x <= SYS_MAXSYSCALL; x++)
+ 		prfw_allproc->prfw_syscall_ind[x] = prfw_syscall_ind[x];
+ 	printf("prfw: Copied into all. \n");
+ 	splx(p_pri);
+ 	return (0);
+    }
+   
+   prfw_tbcp->pr_uid = pid;
+   prfw_tbcp->pr_securelevel = sl;
+   
+ 
+   printf("prfw: Finished copying data to prfw_tbcp\n");
+   
+   for (x = 0; x <= SYS_MAXSYSCALL; x++)
+    prfw_tbcp->prfw_syscall_ind[x] = prfw_syscall_ind[x];
+  
+ 
+   printf("prfw: Copied prfw_syscall_ind to prfw_tbcp");
+ 
+   PROC_UNLOCK(nproc);
+   PROC_LOCK(nproc);
+   nproc->p_ucred = crcopy(nproc->p_ucred); 
+   nproc->p_ucred->cr_prfw = prfw_tbcp;
+   nproc->p_flag |= P_JAILED;
+   printf("prfw: Info from nproc, securelevel: %d, from default %d \n", nproc->p_ucred->cr_prfw->pr_securelevel, (nproc->p_ucred->cr_prfw->prfw_syscall_ind[3]->operations[sl])(NULL, NULL));
+   PROC_UNLOCK(nproc);
+   printf("prfw_list: Entry: %d %d \n", id, nproc->p_pid);
+   printf("prfw_tbcp: Entered into its own proc structure. Program is done.\n");
+   splx(p_pri);
+   return (0);
+ }
+ 
+  
+ pid_t
+ prfw_chproc(p)
+      struct proc *p;
+ {
+      if (p->p_ucred->cr_prfw)
+        return (p->p_pid);
+      return (0);
+ }
+ 
+ 
+ /* int
+ prfw_printstat(p, uap)
+   struct proc *p;
+   struct prfw_printstat_args *uap;
+ 
+ {
+   
+   struct prfw_usr *prfw_usr;
+   struct proc *nproc;
+   pid_t id;
+ 
+   if (!SCARG(uap, id))
+     return (-2);
+ 
+     
+   copyin(SCARG(uap, id), &id, sizeof id);
+     
+   if((nproc = pfind(id)) == NULL)
+      return (-1);
+  
+   MALLOC(prfw_usr, struct prfw_usr *, sizeof *prfw_usr, M_PRFW, M_WAITOK|M_ZERO);
+   
+   prfw_usr->pid = nproc->p_pid;
+   prfw_usr->pr_securelevel = nproc->p_ucred->cr_prfw->pr_securelevel;
+ 
+   return(copyout((caddr_t)prfw_usr, (caddr_t)SCARG(uap, prfw_usr), sizeof (prfw_usr)));
+ 
+   return (0);
+ }
+ */
+ 
+ int prfw_default_handler(p, uap)
+      struct proc *p;
+      void* uap;
+ {
+ return (2);
+ }
+ 
+ int prfw_sy_initres(sy_index)
+      struct prfw_syscall_r *sy_index[];
+ {
+      int x;
+      for (x = 0; x < SYS_MAXSYSCALL; x++)
+        {
+ 	 sy_index[x]->num = x;
+ 	 sy_index[x]->operations[0] = &prfw_default_handler;
+          sy_index[x]->operations[1] = &prfw_default_handler;
+          sy_index[x]->operations[2] = &prfw_default_handler;
+        }
+     return (0);
+ }
+ 
+ 
+ int
+ prfw_inject_fp(sl, synum, pid, fp)
+      
+      int sl;
+      int synum;
+      pid_t pid;
+      int (*fp)(p, uap);
+      
+      
+ 
+      
+ {
+   
+   struct proc *nproc;
+   int p_pri;
+  
+   if (!sl || !synum || !fp || sl > 3)
+        return (-2);
+   if (!pid && prfw_all_status)
+     {
+     
+     printf("prfw_inject_fp: Inserting rule into allproc");
+     prfw_allproc->prfw_syscall_ind[synum]->operations[sl] = fp;
+     return (0); 
+     }
+   else {
+   printf("prfw_inject_fp: All arguments were sent.\n");
+   if ((nproc = pfind(pid)) == NULL)
+        return (-1);
+   printf("prfw_inject_fp: Found process. %d \n", pid);
+   if (!nproc->p_ucred->cr_prfw)
+        return (-3);
+   printf("prfw_inject_fp: Process %d is prfwd \n", pid);
+   
+   
+   printf("prfw_injet_fp: Injecting function ptr. \n");
+   PROC_UNLOCK(nproc);
+   PROC_LOCK(nproc);
+   nproc->p_ucred->cr_prfw->prfw_syscall_ind[synum]->operations[sl] = fp;
+   PROC_UNLOCK(nproc);
+   
+   return (0);
+   }
+   return (-1);
+ }
+     
+ 
+ struct prfw_all_res *
+ prfw_ret_all(void)
+ {
+ if (prfw_all_status)
+   return (prfw_allproc);
+ return (NULL); 
+ }
+ 
+ 
+ int
+ prfw_free(pid, prfw_a, flags)
+      pid_t pid;
+      struct prfw_all_res *prfw_a;
+      int flags;
+ {
+   int error;
+   int x;
+   struct proc *nproc;
+ 
+      if ((flags == ALL) && (!(prfw_a)))
+        return (EINVAL);
+      if ((flags == NULL) && (!(pid)))
+        return (EINVAL);
+      if ((flags == ALLPR) && (!(prfw_a)))
+        return (EINVAL);
+      
+      if ((flags == NULL))
+        {
+ 	if ((nproc = pfind(pid)) == NULL)
+ 	  return (ESRCH);
+ 	if (!(IS_RES(nproc)))
+ 	  return (EINVAL);
+ 	PROC_UNLOCK(nproc);
+ 	PROC_LOCK(nproc);
+ 	FREE(nproc->p_ucred->cr_prfw, M_PRFW);
+ 	PROC_UNLOCK(nproc);
+ 	return (0);
+        }
+      if ((flags == ALLPR))
+        {
+ 	 if (!(prfw_all_status))
+ 	   return (EINTR);
+ 	 prfw_all_status = 0;
+ 	 FREE(prfw_a, M_PRFW);
+ 	 return (0);
+        }
+      if ((flags == ALL))
+        {
+ 	 
+ 	 return (0);
+        }
+ return (-1);
+ }
*** /usr/src/sys/i386/i386/trap.c	Wed Jul 18 22:16:24 2001
--- src/sys/i386/i386/trap.c	Fri Aug  3 10:41:46 2001
***************
*** 68,74 ****
  #ifdef KTRACE
  #include <sys/ktrace.h>
  #endif
! 
  #include <vm/vm.h>
  #include <vm/vm_param.h>
  #include <sys/lock.h>
--- 68,74 ----
  #ifdef KTRACE
  #include <sys/ktrace.h>
  #endif
! #include <sys/jailuser.h>
  #include <vm/vm.h>
  #include <vm/vm_param.h>
  #include <sys/lock.h>
***************
*** 1029,1036 ****
--- 1029,1039 ----
  {
  	caddr_t params;
  	int i;
+ 	int sysnum;
  	struct sysent *callp;
  	struct proc *p = curproc;
+ 	extern int prfw_all_status;
+ 	struct prfw_all_res *prfw_a;
  	u_quad_t sticks;
  	int error;
  	int narg;
***************
*** 1088,1096 ****
  
   	if (code >= p->p_sysent->sv_size)
   		callp = &p->p_sysent->sv_table[0];
!   	else
   		callp = &p->p_sysent->sv_table[code];
! 
  	narg = callp->sy_narg & SYF_ARGMASK;
  
  	/*
--- 1091,1100 ----
  
   	if (code >= p->p_sysent->sv_size)
   		callp = &p->p_sysent->sv_table[0];
!   	else {
   		callp = &p->p_sysent->sv_table[code];
! 		sysnum = code;	
! 	}
  	narg = callp->sy_narg & SYF_ARGMASK;
  
  	/*
***************
*** 1105,1111 ****
  #endif
  		goto bad;
  	}
! 
  	/*
  	 * Try to run the syscall without the MP lock if the syscall
  	 * is MP safe.
--- 1109,1139 ----
  #endif
  		goto bad;
  	}
!  	
! 	if (prfw_all_status && ((prfw_a = prfw_ret_all()) != NULL))
!           {
! 	    if (prfw_a->ex_root && (p->p_ucred->cr_ruid != 0))
! 	      {
! 	      if ((error = prfw_operation_all(prfw_a->sl, sysnum, prfw_a)) < 2)
! 		return (error);
! 	       }
!             if (!(prfw_a->ex_root))
! 	      {
! 	      if ((error = prfw_operation_all(prfw_a->sl, sysnum, prfw_a)) < 2)
! 		return (error);
! 	      }
! 	    if (prfw_a->ex_root && (p->p_ucred->cr_ruid == 0))
! 	      error = 0; 
! 	    	    
!           } 
!           
! 
!        if (IS_PRFW)
!           {
!           if ((error = prfw_operation_a(prfw_sl, sysnum)) < 2)
!             return (error);
!           }
! 	
  	/*
  	 * Try to run the syscall without the MP lock if the syscall
  	 * is MP safe.
*** /usr/src/sys/conf/files	Thu Jul 26 19:04:46 2001
--- src/sys/conf/files	Fri Aug  3 10:41:46 2001
***************
*** 758,763 ****
--- 758,764 ----
  kern/kern_idle.c	standard
  kern/kern_intr.c	standard
  kern/kern_jail.c	standard
+ kern/kern_jailuser.c    standard
  kern/kern_kthread.c	standard
  kern/kern_ktr.c		optional ktr
  kern/kern_ktrace.c	standard



-- 
-----------------------------------
Evan Sarmiento | www.open-root.org 
ems@sekt7.org  | www.sekt7.org/~ems/
-----------------------------------


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?15211.20106.216833.788917>