KEYS: Reinstate EPERM for a key type name beginning with a '.'
[pandora-kernel.git] / security / keys / keyctl.c
index 0b3f5d7..3947cff 100644 (file)
@@ -75,6 +75,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
        if (IS_ERR(description)) {
                ret = PTR_ERR(description);
                goto error;
+       } else if ((description[0] == '.') &&
+                  (strncmp(type, "keyring", 7) == 0)) {
+               ret = -EPERM;
+               goto error2;
        }
 
        /* pull the payload in if one was supplied */
@@ -688,16 +692,16 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 
        /* the key is probably readable - now try to read it */
 can_read_key:
-       ret = key_validate(key);
-       if (ret == 0) {
-               ret = -EOPNOTSUPP;
-               if (key->type->read) {
-                       /* read the data with the semaphore held (since we
-                        * might sleep) */
-                       down_read(&key->sem);
+       ret = -EOPNOTSUPP;
+       if (key->type->read) {
+               /* Read the data with the semaphore held (since we might sleep)
+                * to protect against the key being updated or revoked.
+                */
+               down_read(&key->sem);
+               ret = key_validate(key);
+               if (ret == 0)
                        ret = key->type->read(key, buffer, buflen);
-                       up_read(&key->sem);
-               }
+               up_read(&key->sem);
        }
 
 error2:
@@ -1067,12 +1071,12 @@ long keyctl_instantiate_key_iov(key_serial_t id,
        ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
                                    ARRAY_SIZE(iovstack), iovstack, &iov, 1);
        if (ret < 0)
-               return ret;
+               goto err;
        if (ret == 0)
                goto no_payload_free;
 
        ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
-
+err:
        if (iov != iovstack)
                kfree(iov);
        return ret;