KEYS: DNS: Use key preparsing
authorDavid Howells <dhowells@redhat.com>
Fri, 18 Jul 2014 17:56:36 +0000 (18:56 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 22 Jul 2014 20:46:36 +0000 (21:46 +0100)
Make use of key preparsing in the DNS resolver so that quota size determination
can take place prior to keyring locking when a key is being added.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Steve Dickson <steved@redhat.com>
Acked-by: Jeff Layton <jlayton@primarydata.com>
net/dns_resolver/dns_key.c

index bf85843390488d7768e3b3457c7e9e1139e50c19..f380b2c581781433f2091fec38c7ad77f46f1fae 100644 (file)
@@ -46,7 +46,7 @@ const struct cred *dns_resolver_cache;
 #define        DNS_ERRORNO_OPTION      "dnserror"
 
 /*
- * Instantiate a user defined key for dns_resolver.
+ * Preparse instantiation data for a dns_resolver key.
  *
  * The data must be a NUL-terminated string, with the NUL char accounted in
  * datalen.
@@ -58,17 +58,15 @@ const struct cred *dns_resolver_cache;
  *        "ip1,ip2,...#foo=bar"
  */
 static int
-dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
+dns_resolver_preparse(struct key_preparsed_payload *prep)
 {
        struct user_key_payload *upayload;
        unsigned long derrno;
        int ret;
-       size_t datalen = prep->datalen, result_len = 0;
+       int datalen = prep->datalen, result_len = 0;
        const char *data = prep->data, *end, *opt;
 
-       kenter("%%%d,%s,'%*.*s',%zu",
-              key->serial, key->description,
-              (int)datalen, (int)datalen, data, datalen);
+       kenter("'%*.*s',%u", datalen, datalen, data, datalen);
 
        if (datalen <= 1 || !data || data[datalen - 1] != '\0')
                return -EINVAL;
@@ -95,8 +93,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
                        opt_len = next_opt - opt;
                        if (!opt_len) {
                                printk(KERN_WARNING
-                                      "Empty option to dns_resolver key %d\n",
-                                      key->serial);
+                                      "Empty option to dns_resolver key\n");
                                return -EINVAL;
                        }
 
@@ -125,30 +122,28 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
                                        goto bad_option_value;
 
                                kdebug("dns error no. = %lu", derrno);
-                               key->type_data.x[0] = -derrno;
+                               prep->type_data[0] = ERR_PTR(-derrno);
                                continue;
                        }
 
                bad_option_value:
                        printk(KERN_WARNING
-                              "Option '%*.*s' to dns_resolver key %d:"
+                              "Option '%*.*s' to dns_resolver key:"
                               " bad/missing value\n",
-                              opt_nlen, opt_nlen, opt, key->serial);
+                              opt_nlen, opt_nlen, opt);
                        return -EINVAL;
                } while (opt = next_opt + 1, opt < end);
        }
 
        /* don't cache the result if we're caching an error saying there's no
         * result */
-       if (key->type_data.x[0]) {
-               kleave(" = 0 [h_error %ld]", key->type_data.x[0]);
+       if (prep->type_data[0]) {
+               kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0]));
                return 0;
        }
 
        kdebug("store result");
-       ret = key_payload_reserve(key, result_len);
-       if (ret < 0)
-               return -EINVAL;
+       prep->quotalen = result_len;
 
        upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
        if (!upayload) {
@@ -159,12 +154,22 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
        upayload->datalen = result_len;
        memcpy(upayload->data, data, result_len);
        upayload->data[result_len] = '\0';
-       rcu_assign_pointer(key->payload.data, upayload);
 
+       prep->payload[0] = upayload;
        kleave(" = 0");
        return 0;
 }
 
+/*
+ * Clean up the preparse data
+ */
+static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
+{
+       pr_devel("==>%s()\n", __func__);
+
+       kfree(prep->payload[0]);
+}
+
 /*
  * The description is of the form "[<type>:]<domain_name>"
  *
@@ -234,7 +239,9 @@ static long dns_resolver_read(const struct key *key,
 
 struct key_type key_type_dns_resolver = {
        .name           = "dns_resolver",
-       .instantiate    = dns_resolver_instantiate,
+       .preparse       = dns_resolver_preparse,
+       .free_preparse  = dns_resolver_free_preparse,
+       .instantiate    = generic_key_instantiate,
        .match          = dns_resolver_match,
        .revoke         = user_revoke,
        .destroy        = user_destroy,