Author: des
Date: Tue Oct 18 07:28:58 2011
New Revision: 226495
URL: http://svn.freebsd.org/changeset/base/226495

Log:
  Revisit the capability failure trace points.  The initial implementation
  only logged instances where an operation on a file descriptor required
  capabilities which the file descriptor did not have.  By adding a type enum
  to struct ktr_cap_fail, we can catch other types of capability failures as
  well, such as disallowed system calls or attempts to wrap a file descriptor
  with more capabilities than it had to begin with.

Modified:
  head/sys/kern/kern_ktrace.c
  head/sys/kern/sys_capability.c
  head/sys/kern/vfs_lookup.c
  head/sys/sys/ktrace.h
  head/usr.bin/kdump/kdump.c

Modified: head/sys/kern/kern_ktrace.c
==============================================================================
--- head/sys/kern/kern_ktrace.c Tue Oct 18 07:17:44 2011        (r226494)
+++ head/sys/kern/kern_ktrace.c Tue Oct 18 07:28:58 2011        (r226495)
@@ -772,7 +772,8 @@ ktrstruct(name, data, datalen)
 }
 
 void
-ktrcapfail(needed, held)
+ktrcapfail(type, needed, held)
+       enum ktr_cap_fail_type type;
        cap_rights_t needed;
        cap_rights_t held;
 {
@@ -784,6 +785,7 @@ ktrcapfail(needed, held)
        if (req == NULL)
                return;
        kcf = &req->ktr_data.ktr_cap_fail;
+       kcf->cap_type = type;
        kcf->cap_needed = needed;
        kcf->cap_held = held;
        ktr_enqueuerequest(td, req);

Modified: head/sys/kern/sys_capability.c
==============================================================================
--- head/sys/kern/sys_capability.c      Tue Oct 18 07:17:44 2011        
(r226494)
+++ head/sys/kern/sys_capability.c      Tue Oct 18 07:28:58 2011        
(r226495)
@@ -218,7 +218,7 @@ cap_check(struct capability *c, cap_righ
        if ((c->cap_rights | rights) != c->cap_rights) {
 #ifdef KTRACE
                if (KTRPOINT(curthread, KTR_CAPFAIL))
-                       ktrcapfail(rights, c->cap_rights);
+                       ktrcapfail(CAPFAIL_NOTCAPABLE, rights, c->cap_rights);
 #endif
                return (ENOTCAPABLE);
        }
@@ -314,8 +314,14 @@ kern_capwrap(struct thread *td, struct f
         */
        if (fp->f_type == DTYPE_CAPABILITY) {
                cp_old = fp->f_data;
-               if ((cp_old->cap_rights | rights) != cp_old->cap_rights)
+               if ((cp_old->cap_rights | rights) != cp_old->cap_rights) {
+#ifdef KTRACE
+                       if (KTRPOINT(curthread, KTR_CAPFAIL))
+                               ktrcapfail(CAPFAIL_INCREASE,
+                                   rights, cp_old->cap_rights);
+#endif
                        return (ENOTCAPABLE);
+               }
        }
 
        /*

Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c  Tue Oct 18 07:17:44 2011        (r226494)
+++ head/sys/kern/vfs_lookup.c  Tue Oct 18 07:28:58 2011        (r226495)
@@ -188,8 +188,13 @@ namei(struct nameidata *ndp)
         */
        if (IN_CAPABILITY_MODE(td)) {
                ndp->ni_strictrelative = 1;
-               if (ndp->ni_dirfd == AT_FDCWD)
+               if (ndp->ni_dirfd == AT_FDCWD) {
+#ifdef KTRACE
+                       if (KTRPOINT(td, KTR_CAPFAIL))
+                               ktrcapfail(CAPFAIL_LOOKUP, 0, 0);
+#endif
                        error = ECAPMODE;
+               }
        }
 #endif
        if (error) {
@@ -281,8 +286,13 @@ namei(struct nameidata *ndp)
                if (*(cnp->cn_nameptr) == '/') {
                        vrele(dp);
                        VFS_UNLOCK_GIANT(vfslocked);
-                       if (ndp->ni_strictrelative != 0)
+                       if (ndp->ni_strictrelative != 0) {
+#ifdef KTRACE
+                               if (KTRPOINT(curthread, KTR_CAPFAIL))
+                                       ktrcapfail(CAPFAIL_LOOKUP, 0, 0);
+#endif
                                return (ENOTCAPABLE);
+                       }
                        while (*(cnp->cn_nameptr) == '/') {
                                cnp->cn_nameptr++;
                                ndp->ni_pathlen--;
@@ -644,6 +654,10 @@ dirloop:
         */
        if (cnp->cn_flags & ISDOTDOT) {
                if (ndp->ni_strictrelative != 0) {
+#ifdef KTRACE
+                       if (KTRPOINT(curthread, KTR_CAPFAIL))
+                               ktrcapfail(CAPFAIL_LOOKUP, 0, 0);
+#endif
                        error = ENOTCAPABLE;
                        goto bad;
                }

Modified: head/sys/sys/ktrace.h
==============================================================================
--- head/sys/sys/ktrace.h       Tue Oct 18 07:17:44 2011        (r226494)
+++ head/sys/sys/ktrace.h       Tue Oct 18 07:28:58 2011        (r226495)
@@ -181,7 +181,14 @@ struct ktr_proc_ctor {
  * KTR_CAPFAIL - trace capability check failures
  */
 #define KTR_CAPFAIL    12
+enum ktr_cap_fail_type {
+       CAPFAIL_NOTCAPABLE,     /* insufficient capabilities in cap_check() */
+       CAPFAIL_INCREASE,       /* attempt to increase capabilities */
+       CAPFAIL_SYSCALL,        /* disallowed system call */
+       CAPFAIL_LOOKUP,         /* disallowed VFS lookup */
+};
 struct ktr_cap_fail {
+       enum ktr_cap_fail_type cap_type;
        cap_rights_t    cap_needed;
        cap_rights_t    cap_held;
 };
@@ -230,7 +237,7 @@ void        ktrprocexit(struct thread *);
 void   ktrprocfork(struct proc *, struct proc *);
 void   ktruserret(struct thread *);
 void   ktrstruct(const char *, void *, size_t);
-void   ktrcapfail(cap_rights_t, cap_rights_t);
+void   ktrcapfail(enum ktr_cap_fail_type, cap_rights_t, cap_rights_t);
 #define ktrsockaddr(s) \
        ktrstruct("sockaddr", (s), ((struct sockaddr *)(s))->sa_len)
 #define ktrstat(s) \

Modified: head/usr.bin/kdump/kdump.c
==============================================================================
--- head/usr.bin/kdump/kdump.c  Tue Oct 18 07:17:44 2011        (r226494)
+++ head/usr.bin/kdump/kdump.c  Tue Oct 18 07:28:58 2011        (r226495)
@@ -1592,10 +1592,36 @@ invalid:
 void
 ktrcapfail(struct ktr_cap_fail *ktr)
 {
-       printf("needed ");
-       capname((intmax_t)ktr->cap_needed);
-       printf(" held ");
-       capname((intmax_t)ktr->cap_held);
+       switch (ktr->cap_type) {
+       case CAPFAIL_NOTCAPABLE:
+               /* operation on fd with insufficient capabilities */
+               printf("operation requires ");
+               capname((intmax_t)ktr->cap_needed);
+               printf(", process holds ");
+               capname((intmax_t)ktr->cap_held);
+               break;
+       case CAPFAIL_INCREASE:
+               /* requested more capabilities than fd already has */
+               printf("attempt to increase capabilities from ");
+               capname((intmax_t)ktr->cap_needed);
+               printf(" to ");
+               capname((intmax_t)ktr->cap_held);
+               break;
+       case CAPFAIL_SYSCALL:
+               /* called restricted syscall */
+               printf("disallowed system call");
+               break;
+       case CAPFAIL_LOOKUP:
+               /* used ".." in strict-relative mode */
+               printf("restricted VFS lookup");
+               break;
+       default:
+               printf("unknown capability failure: ");
+               capname((intmax_t)ktr->cap_needed);
+               printf(" ");
+               capname((intmax_t)ktr->cap_held);
+               break;
+       }
 }
 
 #if defined(__amd64__) || defined(__i386__)
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to