Author: emaste
Date: Tue Jun 19 21:26:23 2018
New Revision: 335387
URL: https://svnweb.freebsd.org/changeset/base/335387

Log:
  linuxulator: handle V3 capget/capset
  
  Linux 2.6.26 introduced 64-bit capability sets.  Extend our stub
  implementation to handle both 32- and 64-bit.  (We still report no
  capabilities in capget, and disallow any in capset.)
  
  Reviewed by:  chuck
  Sponsored by: Turing Robotic Industries Inc.
  Differential Revision:        https://reviews.freebsd.org/D15887

Modified:
  head/sys/compat/linux/linux_misc.c

Modified: head/sys/compat/linux/linux_misc.c
==============================================================================
--- head/sys/compat/linux/linux_misc.c  Tue Jun 19 21:07:25 2018        
(r335386)
+++ head/sys/compat/linux/linux_misc.c  Tue Jun 19 21:26:23 2018        
(r335387)
@@ -1867,7 +1867,9 @@ linux_exit_group(struct thread *td, struct linux_exit_
                /* NOTREACHED */
 }
 
-#define _LINUX_CAPABILITY_VERSION  0x19980330
+#define _LINUX_CAPABILITY_VERSION_1  0x19980330
+#define _LINUX_CAPABILITY_VERSION_2  0x20071026
+#define _LINUX_CAPABILITY_VERSION_3  0x20080522
 
 struct l_user_cap_header {
        l_int   version;
@@ -1881,27 +1883,35 @@ struct l_user_cap_data {
 };
 
 int
-linux_capget(struct thread *td, struct linux_capget_args *args)
+linux_capget(struct thread *td, struct linux_capget_args *uap)
 {
        struct l_user_cap_header luch;
-       struct l_user_cap_data lucd;
-       int error;
+       struct l_user_cap_data lucd[2];
+       int error, u32s;
 
-       if (args->hdrp == NULL)
+       if (uap->hdrp == NULL)
                return (EFAULT);
 
-       error = copyin(args->hdrp, &luch, sizeof(luch));
+       error = copyin(uap->hdrp, &luch, sizeof(luch));
        if (error != 0)
                return (error);
 
-       if (luch.version != _LINUX_CAPABILITY_VERSION) {
+       switch (luch.version) {
+       case _LINUX_CAPABILITY_VERSION_1:
+               u32s = 1;
+               break;
+       case _LINUX_CAPABILITY_VERSION_2:
+       case _LINUX_CAPABILITY_VERSION_3:
+               u32s = 2;
+               break;
+       default:
 #ifdef DEBUG
                if (ldebug(capget))
                        printf(LMSG("invalid capget capability version 0x%x"),
                            luch.version);
 #endif
-               luch.version = _LINUX_CAPABILITY_VERSION;
-               error = copyout(&luch, args->hdrp, sizeof(luch));
+               luch.version = _LINUX_CAPABILITY_VERSION_1;
+               error = copyout(&luch, uap->hdrp, sizeof(luch));
                if (error)
                        return (error);
                return (EINVAL);
@@ -1910,42 +1920,50 @@ linux_capget(struct thread *td, struct linux_capget_ar
        if (luch.pid)
                return (EPERM);
 
-       if (args->datap) {
+       if (uap->datap) {
                /*
                 * The current implementation doesn't support setting
                 * a capability (it's essentially a stub) so indicate
                 * that no capabilities are currently set or available
                 * to request.
                 */
-               bzero (&lucd, sizeof(lucd));
-               error = copyout(&lucd, args->datap, sizeof(lucd));
+               memset(&lucd, 0, u32s * sizeof(lucd[0]));
+               error = copyout(&lucd, uap->datap, u32s * sizeof(lucd[0]));
        }
 
        return (error);
 }
 
 int
-linux_capset(struct thread *td, struct linux_capset_args *args)
+linux_capset(struct thread *td, struct linux_capset_args *uap)
 {
        struct l_user_cap_header luch;
-       struct l_user_cap_data lucd;
-       int error;
+       struct l_user_cap_data lucd[2];
+       int error, i, u32s;
 
-       if (args->hdrp == NULL || args->datap == NULL)
+       if (uap->hdrp == NULL || uap->datap == NULL)
                return (EFAULT);
 
-       error = copyin(args->hdrp, &luch, sizeof(luch));
+       error = copyin(uap->hdrp, &luch, sizeof(luch));
        if (error != 0)
                return (error);
 
-       if (luch.version != _LINUX_CAPABILITY_VERSION) {
+       switch (luch.version) {
+       case _LINUX_CAPABILITY_VERSION_1:
+               u32s = 1;
+               break;
+       case _LINUX_CAPABILITY_VERSION_2:
+       case _LINUX_CAPABILITY_VERSION_3:
+               u32s = 2;
+               break;
+       default:
 #ifdef DEBUG
                if (ldebug(capset))
                        printf(LMSG("invalid capset capability version 0x%x"),
                            luch.version);
 #endif
-               luch.version = _LINUX_CAPABILITY_VERSION;
-               error = copyout(&luch, args->hdrp, sizeof(luch));
+               luch.version = _LINUX_CAPABILITY_VERSION_1;
+               error = copyout(&luch, uap->hdrp, sizeof(luch));
                if (error)
                        return (error);
                return (EINVAL);
@@ -1954,18 +1972,21 @@ linux_capset(struct thread *td, struct linux_capset_ar
        if (luch.pid)
                return (EPERM);
 
-       error = copyin(args->datap, &lucd, sizeof(lucd));
+       error = copyin(uap->datap, &lucd, u32s * sizeof(lucd[0]));
        if (error != 0)
                return (error);
 
        /* We currently don't support setting any capabilities. */
-       if (lucd.effective || lucd.permitted || lucd.inheritable) {
-               linux_msg(td,
-                         "capset effective=0x%x, permitted=0x%x, "
-                         "inheritable=0x%x is not implemented",
-                         (int)lucd.effective, (int)lucd.permitted,
-                         (int)lucd.inheritable);
-               return (EPERM);
+       for (i = 0; i < u32s; i++) {
+               if (lucd[i].effective || lucd[i].permitted ||
+                   lucd[i].inheritable) {
+                       linux_msg(td,
+                           "capset[%d] effective=0x%x, permitted=0x%x, "
+                           "inheritable=0x%x is not implemented", i,
+                           (int)lucd[i].effective, (int)lucd[i].permitted,
+                           (int)lucd[i].inheritable);
+                       return (EPERM);
+               }
        }
 
        return (0);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to