1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* user_defined.c: user defined key type
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
5*4882a593Smuzhiyun * Written by David Howells (dhowells@redhat.com)
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/export.h>
9*4882a593Smuzhiyun #include <linux/init.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/seq_file.h>
12*4882a593Smuzhiyun #include <linux/err.h>
13*4882a593Smuzhiyun #include <keys/user-type.h>
14*4882a593Smuzhiyun #include <linux/uaccess.h>
15*4882a593Smuzhiyun #include "internal.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun static int logon_vet_description(const char *desc);
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun /*
20*4882a593Smuzhiyun * user defined keys take an arbitrary string as the description and an
21*4882a593Smuzhiyun * arbitrary blob of data as the payload
22*4882a593Smuzhiyun */
23*4882a593Smuzhiyun struct key_type key_type_user = {
24*4882a593Smuzhiyun .name = "user",
25*4882a593Smuzhiyun .preparse = user_preparse,
26*4882a593Smuzhiyun .free_preparse = user_free_preparse,
27*4882a593Smuzhiyun .instantiate = generic_key_instantiate,
28*4882a593Smuzhiyun .update = user_update,
29*4882a593Smuzhiyun .revoke = user_revoke,
30*4882a593Smuzhiyun .destroy = user_destroy,
31*4882a593Smuzhiyun .describe = user_describe,
32*4882a593Smuzhiyun .read = user_read,
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(key_type_user);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun * This key type is essentially the same as key_type_user, but it does
39*4882a593Smuzhiyun * not define a .read op. This is suitable for storing username and
40*4882a593Smuzhiyun * password pairs in the keyring that you do not want to be readable
41*4882a593Smuzhiyun * from userspace.
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun struct key_type key_type_logon = {
44*4882a593Smuzhiyun .name = "logon",
45*4882a593Smuzhiyun .preparse = user_preparse,
46*4882a593Smuzhiyun .free_preparse = user_free_preparse,
47*4882a593Smuzhiyun .instantiate = generic_key_instantiate,
48*4882a593Smuzhiyun .update = user_update,
49*4882a593Smuzhiyun .revoke = user_revoke,
50*4882a593Smuzhiyun .destroy = user_destroy,
51*4882a593Smuzhiyun .describe = user_describe,
52*4882a593Smuzhiyun .vet_description = logon_vet_description,
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(key_type_logon);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /*
57*4882a593Smuzhiyun * Preparse a user defined key payload
58*4882a593Smuzhiyun */
user_preparse(struct key_preparsed_payload * prep)59*4882a593Smuzhiyun int user_preparse(struct key_preparsed_payload *prep)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun struct user_key_payload *upayload;
62*4882a593Smuzhiyun size_t datalen = prep->datalen;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun if (datalen <= 0 || datalen > 32767 || !prep->data)
65*4882a593Smuzhiyun return -EINVAL;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
68*4882a593Smuzhiyun if (!upayload)
69*4882a593Smuzhiyun return -ENOMEM;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* attach the data */
72*4882a593Smuzhiyun prep->quotalen = datalen;
73*4882a593Smuzhiyun prep->payload.data[0] = upayload;
74*4882a593Smuzhiyun upayload->datalen = datalen;
75*4882a593Smuzhiyun memcpy(upayload->data, prep->data, datalen);
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(user_preparse);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /*
81*4882a593Smuzhiyun * Free a preparse of a user defined key payload
82*4882a593Smuzhiyun */
user_free_preparse(struct key_preparsed_payload * prep)83*4882a593Smuzhiyun void user_free_preparse(struct key_preparsed_payload *prep)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun kfree_sensitive(prep->payload.data[0]);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(user_free_preparse);
88*4882a593Smuzhiyun
user_free_payload_rcu(struct rcu_head * head)89*4882a593Smuzhiyun static void user_free_payload_rcu(struct rcu_head *head)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun struct user_key_payload *payload;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun payload = container_of(head, struct user_key_payload, rcu);
94*4882a593Smuzhiyun kfree_sensitive(payload);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /*
98*4882a593Smuzhiyun * update a user defined key
99*4882a593Smuzhiyun * - the key's semaphore is write-locked
100*4882a593Smuzhiyun */
user_update(struct key * key,struct key_preparsed_payload * prep)101*4882a593Smuzhiyun int user_update(struct key *key, struct key_preparsed_payload *prep)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun struct user_key_payload *zap = NULL;
104*4882a593Smuzhiyun int ret;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* check the quota and attach the new data */
107*4882a593Smuzhiyun ret = key_payload_reserve(key, prep->datalen);
108*4882a593Smuzhiyun if (ret < 0)
109*4882a593Smuzhiyun return ret;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* attach the new data, displacing the old */
112*4882a593Smuzhiyun key->expiry = prep->expiry;
113*4882a593Smuzhiyun if (key_is_positive(key))
114*4882a593Smuzhiyun zap = dereference_key_locked(key);
115*4882a593Smuzhiyun rcu_assign_keypointer(key, prep->payload.data[0]);
116*4882a593Smuzhiyun prep->payload.data[0] = NULL;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (zap)
119*4882a593Smuzhiyun call_rcu(&zap->rcu, user_free_payload_rcu);
120*4882a593Smuzhiyun return ret;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(user_update);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /*
125*4882a593Smuzhiyun * dispose of the links from a revoked keyring
126*4882a593Smuzhiyun * - called with the key sem write-locked
127*4882a593Smuzhiyun */
user_revoke(struct key * key)128*4882a593Smuzhiyun void user_revoke(struct key *key)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun struct user_key_payload *upayload = user_key_payload_locked(key);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /* clear the quota */
133*4882a593Smuzhiyun key_payload_reserve(key, 0);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun if (upayload) {
136*4882a593Smuzhiyun rcu_assign_keypointer(key, NULL);
137*4882a593Smuzhiyun call_rcu(&upayload->rcu, user_free_payload_rcu);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun EXPORT_SYMBOL(user_revoke);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /*
144*4882a593Smuzhiyun * dispose of the data dangling from the corpse of a user key
145*4882a593Smuzhiyun */
user_destroy(struct key * key)146*4882a593Smuzhiyun void user_destroy(struct key *key)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun struct user_key_payload *upayload = key->payload.data[0];
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun kfree_sensitive(upayload);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(user_destroy);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /*
156*4882a593Smuzhiyun * describe the user key
157*4882a593Smuzhiyun */
user_describe(const struct key * key,struct seq_file * m)158*4882a593Smuzhiyun void user_describe(const struct key *key, struct seq_file *m)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun seq_puts(m, key->description);
161*4882a593Smuzhiyun if (key_is_positive(key))
162*4882a593Smuzhiyun seq_printf(m, ": %u", key->datalen);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(user_describe);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun * read the key data
169*4882a593Smuzhiyun * - the key's semaphore is read-locked
170*4882a593Smuzhiyun */
user_read(const struct key * key,char * buffer,size_t buflen)171*4882a593Smuzhiyun long user_read(const struct key *key, char *buffer, size_t buflen)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun const struct user_key_payload *upayload;
174*4882a593Smuzhiyun long ret;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun upayload = user_key_payload_locked(key);
177*4882a593Smuzhiyun ret = upayload->datalen;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* we can return the data as is */
180*4882a593Smuzhiyun if (buffer && buflen > 0) {
181*4882a593Smuzhiyun if (buflen > upayload->datalen)
182*4882a593Smuzhiyun buflen = upayload->datalen;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun memcpy(buffer, upayload->data, buflen);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun return ret;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(user_read);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /* Vet the description for a "logon" key */
logon_vet_description(const char * desc)193*4882a593Smuzhiyun static int logon_vet_description(const char *desc)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun char *p;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* require a "qualified" description string */
198*4882a593Smuzhiyun p = strchr(desc, ':');
199*4882a593Smuzhiyun if (!p)
200*4882a593Smuzhiyun return -EINVAL;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun /* also reject description with ':' as first char */
203*4882a593Smuzhiyun if (p == desc)
204*4882a593Smuzhiyun return -EINVAL;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun return 0;
207*4882a593Smuzhiyun }
208