[PATCH] key: plug request_key_auth memleak
[linux-2.6.git] / security / keys / request_key_auth.c
1 /* request_key_auth.c: request key authorisation controlling key def
2  *
3  * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <linux/module.h>
13 #include <linux/sched.h>
14 #include <linux/err.h>
15 #include <linux/seq_file.h>
16 #include "internal.h"
17
18 static int request_key_auth_instantiate(struct key *, const void *, size_t);
19 static void request_key_auth_describe(const struct key *, struct seq_file *);
20 static void request_key_auth_destroy(struct key *);
21
22 /*
23  * the request-key authorisation key type definition
24  */
25 struct key_type key_type_request_key_auth = {
26         .name           = ".request_key_auth",
27         .def_datalen    = sizeof(struct request_key_auth),
28         .instantiate    = request_key_auth_instantiate,
29         .describe       = request_key_auth_describe,
30         .destroy        = request_key_auth_destroy,
31 };
32
33 /*****************************************************************************/
34 /*
35  * instantiate a request-key authorisation record
36  */
37 static int request_key_auth_instantiate(struct key *key,
38                                         const void *data,
39                                         size_t datalen)
40 {
41         struct request_key_auth *rka, *irka;
42         struct key *instkey;
43         int ret;
44
45         ret = -ENOMEM;
46         rka = kmalloc(sizeof(*rka), GFP_KERNEL);
47         if (rka) {
48                 /* see if the calling process is already servicing the key
49                  * request of another process */
50                 instkey = key_get_instantiation_authkey(0);
51                 if (!IS_ERR(instkey)) {
52                         /* it is - use that instantiation context here too */
53                         irka = instkey->payload.data;
54                         rka->context = irka->context;
55                         rka->pid = irka->pid;
56                         key_put(instkey);
57                 }
58                 else {
59                         /* it isn't - use this process as the context */
60                         rka->context = current;
61                         rka->pid = current->pid;
62                 }
63
64                 rka->target_key = key_get((struct key *) data);
65                 key->payload.data = rka;
66                 ret = 0;
67         }
68
69         return ret;
70
71 } /* end request_key_auth_instantiate() */
72
73 /*****************************************************************************/
74 /*
75  *
76  */
77 static void request_key_auth_describe(const struct key *key,
78                                       struct seq_file *m)
79 {
80         struct request_key_auth *rka = key->payload.data;
81
82         seq_puts(m, "key:");
83         seq_puts(m, key->description);
84         seq_printf(m, " pid:%d", rka->pid);
85
86 } /* end request_key_auth_describe() */
87
88 /*****************************************************************************/
89 /*
90  * destroy an instantiation authorisation token key
91  */
92 static void request_key_auth_destroy(struct key *key)
93 {
94         struct request_key_auth *rka = key->payload.data;
95
96         kenter("{%d}", key->serial);
97
98         key_put(rka->target_key);
99         kfree(rka);
100
101 } /* end request_key_auth_destroy() */
102
103 /*****************************************************************************/
104 /*
105  * create a session keyring to be for the invokation of /sbin/request-key and
106  * stick an authorisation token in it
107  */
108 struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
109 {
110         struct key *keyring, *rkakey = NULL;
111         char desc[20];
112         int ret;
113
114         kenter("%d,", target->serial);
115
116         /* allocate a new session keyring */
117         sprintf(desc, "_req.%u", target->serial);
118
119         keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
120         if (IS_ERR(keyring)) {
121                 kleave("= %ld", PTR_ERR(keyring));
122                 return keyring;
123         }
124
125         /* allocate the auth key */
126         sprintf(desc, "%x", target->serial);
127
128         rkakey = key_alloc(&key_type_request_key_auth, desc,
129                            current->fsuid, current->fsgid,
130                            KEY_POS_VIEW | KEY_USR_VIEW, 1);
131         if (IS_ERR(rkakey)) {
132                 key_put(keyring);
133                 kleave("= %ld", PTR_ERR(rkakey));
134                 return rkakey;
135         }
136
137         /* construct and attach to the keyring */
138         ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL);
139         if (ret < 0) {
140                 key_revoke(rkakey);
141                 key_put(rkakey);
142                 key_put(keyring);
143                 kleave("= %d", ret);
144                 return ERR_PTR(ret);
145         }
146
147         *_rkakey = rkakey;
148         kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial);
149         return keyring;
150
151 } /* end request_key_auth_new() */
152
153 /*****************************************************************************/
154 /*
155  * get the authorisation key for instantiation of a specific key if attached to
156  * the current process's keyrings
157  * - this key is inserted into a keyring and that is set as /sbin/request-key's
158  *   session keyring
159  * - a target_id of zero specifies any valid token
160  */
161 struct key *key_get_instantiation_authkey(key_serial_t target_id)
162 {
163         struct task_struct *tsk = current;
164         struct key *instkey;
165
166         /* we must have our own personal session keyring */
167         if (!tsk->signal->session_keyring)
168                 return ERR_PTR(-EACCES);
169
170         /* and it must contain a suitable request authorisation key
171          * - lock RCU against session keyring changing
172          */
173         rcu_read_lock();
174
175         instkey = keyring_search_instkey(
176                 rcu_dereference(tsk->signal->session_keyring), target_id);
177
178         rcu_read_unlock();
179         return instkey;
180
181 } /* end key_get_instantiation_authkey() */