Linux: Fix return codes from setpag
[openafs.git] / src / afs / LINUX / osi_groups.c
index f5a0bd2..7561ecc 100644 (file)
@@ -168,13 +168,14 @@ __setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag,
 extern struct key_type key_type_keyring __attribute__((weak));
 static struct key_type *__key_type_keyring = &key_type_keyring;
 
+/* install_session_keyring returns negative error values */
 static int
 install_session_keyring(struct key *keyring)
 {
     struct key *old;
     char desc[20];
     int code = -EINVAL;
-    int flags;
+    unsigned long flags;
 
     if (!__key_type_keyring)
        return code;
@@ -225,6 +226,12 @@ out:
 }
 #endif /* LINUX_KEYRING_SUPPORT */
 
+/* Error codes from setpag must be positive, otherwise they don't
+ * make it back into userspace properly. Error codes from the
+ * Linux keyring utilities, and from install_session_keyring()
+ * are negative. So we need to be careful to convert them correctly
+ * here
+ */
 int
 setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag,
        int change_parent)
@@ -255,6 +262,8 @@ setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag,
                code = PTR_ERR(key);
            }
        }
+       if (code)
+           code = -code;
     }
 #endif /* LINUX_KEYRING_SUPPORT */
 
@@ -272,31 +281,28 @@ afs_xsetgroups(int gidsetsize, gid_t * grouplist)
     afs_uint32 junk;
     int old_pag;
 
-    lock_kernel();
     old_pag = PagInCred(cr);
     crfree(cr);
-    unlock_kernel();
 
     code = (*sys_setgroupsp) (gidsetsize, grouplist);
     if (code) {
        return code;
     }
 
-    lock_kernel();
     cr = crref();
     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
        /* re-install old pag if there's room. */
        code = __setpag(&cr, old_pag, &junk, 0);
     }
     crfree(cr);
-    unlock_kernel();
 
     /* Linux syscall ABI returns errno as negative */
     return (-code);
 }
 
 /* Intercept the standard uid32 system call. */
-extern asmlinkage long (*sys_setgroups32p) (int gidsetsize, gid_t * grouplist);
+extern asmlinkage int (*sys_setgroups32p) (int gidsetsize,
+                                          __kernel_gid32_t * grouplist);
 asmlinkage long
 afs_xsetgroups32(int gidsetsize, gid_t * grouplist)
 {
@@ -305,10 +311,8 @@ afs_xsetgroups32(int gidsetsize, gid_t * grouplist)
     afs_uint32 junk;
     int old_pag;
 
-    lock_kernel();
     old_pag = PagInCred(cr);
     crfree(cr);
-    unlock_kernel();
 
     code = (*sys_setgroups32p) (gidsetsize, grouplist);
 
@@ -316,14 +320,12 @@ afs_xsetgroups32(int gidsetsize, gid_t * grouplist)
        return code;
     }
 
-    lock_kernel();
     cr = crref();
     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
        /* re-install old pag if there's room. */
        code = __setpag(&cr, old_pag, &junk, 0);
     }
     crfree(cr);
-    unlock_kernel();
 
     /* Linux syscall ABI returns errno as negative */
     return (-code);
@@ -331,7 +333,7 @@ afs_xsetgroups32(int gidsetsize, gid_t * grouplist)
 
 #if defined(AFS_PPC64_LINUX20_ENV)
 /* Intercept the uid16 system call as used by 32bit programs. */
-extern long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
+extern asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
 asmlinkage long afs32_xsetgroups(int gidsetsize, gid_t *grouplist)
 {
     long code;
@@ -339,24 +341,20 @@ asmlinkage long afs32_xsetgroups(int gidsetsize, gid_t *grouplist)
     afs_uint32 junk;
     int old_pag;
     
-    lock_kernel();
     old_pag = PagInCred(cr);
     crfree(cr);
-    unlock_kernel();
     
     code = (*sys32_setgroupsp)(gidsetsize, grouplist);
     if (code) {
        return code;
     }
     
-    lock_kernel();
     cr = crref();
     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
        /* re-install old pag if there's room. */
        code = __setpag(&cr, old_pag, &junk, 0);
     }
     crfree(cr);
-    unlock_kernel();
     
     /* Linux syscall ABI returns errno as negative */
     return (-code);
@@ -365,7 +363,13 @@ asmlinkage long afs32_xsetgroups(int gidsetsize, gid_t *grouplist)
 
 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_AMD64_LINUX20_ENV)
 /* Intercept the uid16 system call as used by 32bit programs. */
-extern long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
+#ifdef AFS_AMD64_LINUX20_ENV
+extern asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
+#endif /* AFS_AMD64_LINUX20_ENV */
+#ifdef AFS_SPARC64_LINUX26_ENV
+extern asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
+                                          __kernel_gid32_t * grouplist);
+#endif /* AFS_SPARC64_LINUX26_ENV */
 asmlinkage long
 afs32_xsetgroups(int gidsetsize, u16 * grouplist)
 {
@@ -374,31 +378,33 @@ afs32_xsetgroups(int gidsetsize, u16 * grouplist)
     afs_uint32 junk;
     int old_pag;
     
-    lock_kernel();
     old_pag = PagInCred(cr);
     crfree(cr);
-    unlock_kernel();
     
     code = (*sys32_setgroupsp) (gidsetsize, grouplist);
     if (code) {
        return code;
     }
     
-    lock_kernel();
     cr = crref();
     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
        /* re-install old pag if there's room. */
        code = __setpag(&cr, old_pag, &junk, 0);
     }
     crfree(cr);
-    unlock_kernel();
     
     /* Linux syscall ABI returns errno as negative */
     return (-code);
 }
 
 /* Intercept the uid32 system call as used by 32bit programs. */
-extern long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
+#ifdef AFS_AMD64_LINUX20_ENV
+extern asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
+#endif /* AFS_AMD64_LINUX20_ENV */
+#ifdef AFS_SPARC64_LINUX26_ENV
+extern asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
+                                            __kernel_gid32_t * grouplist);
+#endif /* AFS_SPARC64_LINUX26_ENV */
 asmlinkage long
 afs32_xsetgroups32(int gidsetsize, gid_t * grouplist)
 {
@@ -407,24 +413,20 @@ afs32_xsetgroups32(int gidsetsize, gid_t * grouplist)
     afs_uint32 junk;
     int old_pag;
 
-    lock_kernel();
     old_pag = PagInCred(cr);
     crfree(cr);
-    unlock_kernel();
 
     code = (*sys32_setgroups32p) (gidsetsize, grouplist);
     if (code) {
        return code;
     }
 
-    lock_kernel();
     cr = crref();
     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
        /* re-install old pag if there's room. */
        code = __setpag(&cr, old_pag, &junk, 0);
     }
     crfree(cr);
-    unlock_kernel();
 
     /* Linux syscall ABI returns errno as negative */
     return (-code);