Skip to content

Commit 2ef7ade

Browse files
evelikovlucasdemarchi
authored andcommitted
libkmod/libkmod-signature: rework struct kmod_signature_info
Currently, we use a stack allocated instance which bolts of misc private data via a void *, while also having an optional free callback. In kmod we opt to pre-calculate the total size, do a one-off allocation, copy the data as needed, adjusting the pointers. Doing the same here, gives us a mixed bag of benefits: - shorter and simpler code - smaller binary - ~100 bytes off - fewer instructions - ~40 per module - few allocations - ~2 per module - extra bytes are allocated - ~180 per module The updated code seems far more natural and consistent with the code-base. Although, if we really want to squeeze more cycles we could use a reasonably large stack buffer and fallback to heap. v2: - don't leak on d2i_PKCS7_bio failure - use +1 (instead of sizeof('\0')) for the null terminator Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com> Link: #427 Signed-off-by: Lucas De Marchi <demarchi@kernel.org>
1 parent 9585b87 commit 2ef7ade

3 files changed

Lines changed: 98 additions & 94 deletions

File tree

libkmod/libkmod-internal.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,8 @@ struct kmod_signature_info {
173173
const char *hash_algo, *id_type;
174174
const char *sig;
175175
size_t sig_len;
176-
void (*free)(void *);
177-
void *private;
178176
};
179-
_must_check_ _nonnull_all_ bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info);
180-
_nonnull_all_ void kmod_module_signature_info_free(struct kmod_signature_info *sig_info);
177+
_must_check_ _nonnull_all_ bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info **sig_info);
181178

182179
/* libkmod-builtin.c */
183180
_nonnull_all_ ssize_t kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, char ***modinfo);

libkmod/libkmod-module.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1869,7 +1869,7 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod,
18691869
{
18701870
char **strings;
18711871
int i, count, ret = -ENOMEM;
1872-
struct kmod_signature_info sig_info = {};
1872+
struct kmod_signature_info *sig_info = NULL;
18731873

18741874
if (mod == NULL || list == NULL)
18751875
return -ENOENT;
@@ -1918,36 +1918,36 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod,
19181918
struct kmod_list *n;
19191919

19201920
n = kmod_module_info_append(list, "sig_id", strlen("sig_id"),
1921-
sig_info.id_type, strlen(sig_info.id_type));
1921+
sig_info->id_type, strlen(sig_info->id_type));
19221922
if (n == NULL)
19231923
goto list_error;
19241924
count++;
19251925

19261926
n = kmod_module_info_append(list, "signer", strlen("signer"),
1927-
sig_info.signer, sig_info.signer_len);
1927+
sig_info->signer, sig_info->signer_len);
19281928
if (n == NULL)
19291929
goto list_error;
19301930
count++;
19311931

19321932
n = kmod_module_info_append_hex(list, "sig_key", strlen("sig_key"),
1933-
sig_info.key_id, sig_info.key_id_len);
1933+
sig_info->key_id, sig_info->key_id_len);
19341934
if (n == NULL)
19351935
goto list_error;
19361936
count++;
19371937

19381938
n = kmod_module_info_append(list, "sig_hashalgo", strlen("sig_hashalgo"),
1939-
sig_info.hash_algo,
1940-
strlen(sig_info.hash_algo));
1939+
sig_info->hash_algo,
1940+
strlen(sig_info->hash_algo));
19411941
if (n == NULL)
19421942
goto list_error;
19431943
count++;
19441944

19451945
/*
1946-
* Omit sig_info.algo for now, as these
1946+
* Omit sig_info->algo for now, as these
19471947
* are currently constant.
19481948
*/
19491949
n = kmod_module_info_append_hex(list, "signature", strlen("signature"),
1950-
sig_info.sig, sig_info.sig_len);
1950+
sig_info->sig, sig_info->sig_len);
19511951

19521952
if (n == NULL)
19531953
goto list_error;
@@ -1957,7 +1957,7 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod,
19571957

19581958
list_error:
19591959
/* aux structures freed in normal case also */
1960-
kmod_module_signature_info_free(&sig_info);
1960+
free(sig_info);
19611961

19621962
if (ret < 0) {
19631963
kmod_module_info_free_list(*list);

libkmod/libkmod-signature.c

Lines changed: 88 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,12 @@ struct module_signature {
8383

8484
static bool fill_default(const char *mem, off_t size,
8585
const struct module_signature *modsig, size_t sig_len,
86-
struct kmod_signature_info *sig_info)
86+
struct kmod_signature_info **out_sig_info)
8787
{
88+
struct kmod_signature_info *sig_info = calloc(1, sizeof(*sig_info));
89+
if (sig_info == NULL)
90+
return false;
91+
8892
size -= sig_len;
8993
sig_info->sig = mem + size;
9094
sig_info->sig_len = sig_len;
@@ -99,31 +103,13 @@ static bool fill_default(const char *mem, off_t size,
99103

100104
sig_info->hash_algo = pkey_hash_algo[modsig->hash];
101105

106+
*out_sig_info = sig_info;
107+
102108
return true;
103109
}
104110

105111
#if ENABLE_OPENSSL
106112

107-
struct pkcs7_private {
108-
PKCS7 *pkcs7;
109-
char *key_id;
110-
BIGNUM *sno;
111-
char *hash_algo;
112-
};
113-
114-
static void pkcs7_free(void *s)
115-
{
116-
struct kmod_signature_info *si = s;
117-
struct pkcs7_private *pvt = si->private;
118-
119-
PKCS7_free(pvt->pkcs7);
120-
BN_free(pvt->sno);
121-
free(pvt->key_id);
122-
free(pvt->hash_algo);
123-
free(pvt);
124-
si->private = NULL;
125-
}
126-
127113
static const char *x509_name_to_str(X509_NAME *name)
128114
{
129115
int i;
@@ -150,8 +136,10 @@ static const char *x509_name_to_str(X509_NAME *name)
150136
}
151137

152138
static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len,
153-
struct kmod_signature_info *sig_info)
139+
struct kmod_signature_info **out_sig_info)
154140
{
141+
struct kmod_signature_info *sig_info;
142+
char *p;
155143
const char *pkcs7_raw;
156144
PKCS7 *pkcs7;
157145
STACK_OF(PKCS7_SIGNER_INFO) * sis;
@@ -162,26 +150,21 @@ static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len,
162150
X509_ALGOR *dig_alg;
163151
const ASN1_OBJECT *o;
164152
BIO *in;
165-
int len;
166-
char *key_id_str;
167-
struct pkcs7_private *pvt;
168153
const char *issuer_str;
169-
char *hash_algo;
170154
int hash_algo_len;
155+
size_t total_len;
171156

172157
size -= sig_len;
173158
pkcs7_raw = mem + size;
174159

175160
in = BIO_new_mem_buf(pkcs7_raw, sig_len);
176161

177162
pkcs7 = d2i_PKCS7_bio(in, NULL);
178-
if (pkcs7 == NULL) {
179-
BIO_free(in);
180-
return false;
181-
}
182-
183163
BIO_free(in);
184164

165+
if (pkcs7 == NULL)
166+
goto err;
167+
185168
sis = PKCS7_get_signer_info(pkcs7);
186169
if (sis == NULL)
187170
goto err;
@@ -191,66 +174,86 @@ static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len,
191174
goto err;
192175

193176
is = si->issuer_and_serial;
194-
sig = si->enc_digest;
195177

196-
PKCS7_SIGNER_INFO_get0_algs(si, NULL, &dig_alg, NULL);
178+
/* Calculate the total length */
179+
total_len = sizeof(struct kmod_signature_info);
197180

198-
sig_info->sig = (const char *)ASN1_STRING_get0_data(sig);
199-
sig_info->sig_len = ASN1_STRING_length(sig);
181+
/* signer */
182+
issuer_str = x509_name_to_str(is->issuer);
183+
if (issuer_str != NULL)
184+
total_len += strlen(issuer_str);
200185

186+
/* key_id */
201187
sno_bn = ASN1_INTEGER_to_BN(is->serial, NULL);
202188
if (sno_bn == NULL)
203189
goto err;
204190

205-
len = BN_num_bytes(sno_bn);
206-
key_id_str = malloc(len);
207-
if (key_id_str == NULL)
208-
goto err2;
209-
BN_bn2bin(sno_bn, (unsigned char *)key_id_str);
191+
total_len += BN_num_bytes(sno_bn);
210192

211-
sig_info->key_id = key_id_str;
212-
sig_info->key_id_len = len;
193+
/* hash_algo */
194+
PKCS7_SIGNER_INFO_get0_algs(si, NULL, &dig_alg, NULL);
195+
X509_ALGOR_get0(&o, NULL, NULL, dig_alg);
196+
hash_algo_len = OBJ_obj2txt(NULL, 0, o, 0);
197+
if (hash_algo_len < 0)
198+
goto err1;
213199

214-
issuer_str = x509_name_to_str(is->issuer);
200+
total_len += hash_algo_len + 1;
201+
202+
/* sig */
203+
sig = si->enc_digest;
204+
total_len += ASN1_STRING_length(sig);
205+
206+
sig_info = calloc(1, total_len);
207+
if (sig_info == NULL)
208+
goto err1;
209+
210+
p = (char *)sig_info;
211+
212+
p += sizeof(struct kmod_signature_info);
213+
214+
/* signer */
215215
if (issuer_str != NULL) {
216-
sig_info->signer = issuer_str;
216+
sig_info->signer = p;
217217
sig_info->signer_len = strlen(issuer_str);
218+
219+
memcpy(p, issuer_str, sig_info->signer_len);
220+
p += sig_info->signer_len;
218221
}
219222

220-
X509_ALGOR_get0(&o, NULL, NULL, dig_alg);
223+
/* key_id */
224+
sig_info->key_id = p;
225+
sig_info->key_id_len = BN_num_bytes(sno_bn);
221226

222-
// Use OBJ_obj2txt to calculate string length
223-
hash_algo_len = OBJ_obj2txt(NULL, 0, o, 0);
224-
if (hash_algo_len < 0)
225-
goto err3;
226-
hash_algo = malloc(hash_algo_len + 1);
227-
if (hash_algo == NULL)
228-
goto err3;
229-
hash_algo_len = OBJ_obj2txt(hash_algo, hash_algo_len + 1, o, 0);
227+
BN_bn2bin(sno_bn, (unsigned char *)p);
228+
p += sig_info->key_id_len;
229+
230+
/* hash_algo */
231+
sig_info->hash_algo = p;
232+
233+
hash_algo_len = OBJ_obj2txt(p, hash_algo_len + 1, o, 0);
230234
if (hash_algo_len < 0)
231-
goto err4;
235+
goto err2;
236+
p += hash_algo_len;
232237

233-
// Assign libcrypto hash algo string or number
234-
sig_info->hash_algo = hash_algo;
238+
*p = '\0';
239+
p++;
235240

236-
pvt = malloc(sizeof(*pvt));
237-
if (pvt == NULL)
238-
goto err4;
241+
/* sig */
242+
sig_info->sig = p;
243+
sig_info->sig_len = ASN1_STRING_length(sig);
244+
245+
memcpy(p, ASN1_STRING_get0_data(sig), sig_info->sig_len);
239246

240-
pvt->pkcs7 = pkcs7;
241-
pvt->key_id = key_id_str;
242-
pvt->sno = sno_bn;
243-
pvt->hash_algo = hash_algo;
244-
sig_info->private = pvt;
247+
BN_free(sno_bn);
248+
PKCS7_free(pkcs7);
245249

246-
sig_info->free = pkcs7_free;
250+
*out_sig_info = sig_info;
247251

248252
return true;
249-
err4:
250-
free(hash_algo);
251-
err3:
252-
free(key_id_str);
253+
253254
err2:
255+
free(sig_info);
256+
err1:
254257
BN_free(sno_bn);
255258
err:
256259
PKCS7_free(pkcs7);
@@ -260,9 +263,14 @@ static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len,
260263
#else
261264

262265
static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len,
263-
struct kmod_signature_info *sig_info)
266+
struct kmod_signature_info **out_sig_info)
264267
{
268+
struct kmod_signature_info *sig_info = calloc(1, sizeof(*sig_info));
269+
if (sig_info == NULL)
270+
return false;
271+
265272
sig_info->hash_algo = "unknown";
273+
*out_sig_info = sig_info;
266274
return true;
267275
}
268276

@@ -282,14 +290,14 @@ static bool fill_pkcs7(const char *mem, off_t size, size_t sig_len,
282290
*/
283291

284292
bool kmod_module_signature_info(const struct kmod_file *file,
285-
struct kmod_signature_info *sig_info)
293+
struct kmod_signature_info **sig_info)
286294
{
287295
const char *mem;
288296
const void *contents;
289297
off_t size;
290298
struct module_signature modsig;
291299
size_t sig_len;
292-
int ret;
300+
bool ret;
293301

294302
ret = kmod_file_get_contents(file, &contents, &size);
295303
if (ret)
@@ -318,18 +326,17 @@ bool kmod_module_signature_info(const struct kmod_file *file,
318326
size < (int64_t)sig_len + modsig.signer_len + modsig.key_id_len)
319327
return false;
320328

321-
sig_info->id_type = pkey_id_type[modsig.id_type];
322-
323329
switch (modsig.id_type) {
324330
case PKEY_ID_PKCS7:
325-
return fill_pkcs7(mem, size, sig_len, sig_info);
331+
ret = fill_pkcs7(mem, size, sig_len, sig_info);
332+
break;
326333
default:
327-
return fill_default(mem, size, &modsig, sig_len, sig_info);
334+
ret = fill_default(mem, size, &modsig, sig_len, sig_info);
335+
break;
328336
}
329-
}
330337

331-
void kmod_module_signature_info_free(struct kmod_signature_info *sig_info)
332-
{
333-
if (sig_info->free)
334-
sig_info->free(sig_info);
338+
if (ret)
339+
(*sig_info)->id_type = pkey_id_type[modsig.id_type];
340+
341+
return ret;
335342
}

0 commit comments

Comments
 (0)