1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2008 IBM Corporation
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Mimi Zohar <zohar@us.ibm.com>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * File: ima_api.c
8*4882a593Smuzhiyun * Implements must_appraise_or_measure, collect_measurement,
9*4882a593Smuzhiyun * appraise_measurement, store_measurement and store_template.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/file.h>
13*4882a593Smuzhiyun #include <linux/fs.h>
14*4882a593Smuzhiyun #include <linux/xattr.h>
15*4882a593Smuzhiyun #include <linux/evm.h>
16*4882a593Smuzhiyun #include <linux/iversion.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "ima.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun * ima_free_template_entry - free an existing template entry
22*4882a593Smuzhiyun */
ima_free_template_entry(struct ima_template_entry * entry)23*4882a593Smuzhiyun void ima_free_template_entry(struct ima_template_entry *entry)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun int i;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun for (i = 0; i < entry->template_desc->num_fields; i++)
28*4882a593Smuzhiyun kfree(entry->template_data[i].data);
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun kfree(entry->digests);
31*4882a593Smuzhiyun kfree(entry);
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun * ima_alloc_init_template - create and initialize a new template entry
36*4882a593Smuzhiyun */
ima_alloc_init_template(struct ima_event_data * event_data,struct ima_template_entry ** entry,struct ima_template_desc * desc)37*4882a593Smuzhiyun int ima_alloc_init_template(struct ima_event_data *event_data,
38*4882a593Smuzhiyun struct ima_template_entry **entry,
39*4882a593Smuzhiyun struct ima_template_desc *desc)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun struct ima_template_desc *template_desc;
42*4882a593Smuzhiyun struct tpm_digest *digests;
43*4882a593Smuzhiyun int i, result = 0;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun if (desc)
46*4882a593Smuzhiyun template_desc = desc;
47*4882a593Smuzhiyun else
48*4882a593Smuzhiyun template_desc = ima_template_desc_current();
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun *entry = kzalloc(struct_size(*entry, template_data,
51*4882a593Smuzhiyun template_desc->num_fields), GFP_NOFS);
52*4882a593Smuzhiyun if (!*entry)
53*4882a593Smuzhiyun return -ENOMEM;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
56*4882a593Smuzhiyun sizeof(*digests), GFP_NOFS);
57*4882a593Smuzhiyun if (!digests) {
58*4882a593Smuzhiyun kfree(*entry);
59*4882a593Smuzhiyun *entry = NULL;
60*4882a593Smuzhiyun return -ENOMEM;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun (*entry)->digests = digests;
64*4882a593Smuzhiyun (*entry)->template_desc = template_desc;
65*4882a593Smuzhiyun for (i = 0; i < template_desc->num_fields; i++) {
66*4882a593Smuzhiyun const struct ima_template_field *field =
67*4882a593Smuzhiyun template_desc->fields[i];
68*4882a593Smuzhiyun u32 len;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun result = field->field_init(event_data,
71*4882a593Smuzhiyun &((*entry)->template_data[i]));
72*4882a593Smuzhiyun if (result != 0)
73*4882a593Smuzhiyun goto out;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun len = (*entry)->template_data[i].len;
76*4882a593Smuzhiyun (*entry)->template_data_len += sizeof(len);
77*4882a593Smuzhiyun (*entry)->template_data_len += len;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun return 0;
80*4882a593Smuzhiyun out:
81*4882a593Smuzhiyun ima_free_template_entry(*entry);
82*4882a593Smuzhiyun *entry = NULL;
83*4882a593Smuzhiyun return result;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /*
87*4882a593Smuzhiyun * ima_store_template - store ima template measurements
88*4882a593Smuzhiyun *
89*4882a593Smuzhiyun * Calculate the hash of a template entry, add the template entry
90*4882a593Smuzhiyun * to an ordered list of measurement entries maintained inside the kernel,
91*4882a593Smuzhiyun * and also update the aggregate integrity value (maintained inside the
92*4882a593Smuzhiyun * configured TPM PCR) over the hashes of the current list of measurement
93*4882a593Smuzhiyun * entries.
94*4882a593Smuzhiyun *
95*4882a593Smuzhiyun * Applications retrieve the current kernel-held measurement list through
96*4882a593Smuzhiyun * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
97*4882a593Smuzhiyun * TPM PCR (called quote) can be retrieved using a TPM user space library
98*4882a593Smuzhiyun * and is used to validate the measurement list.
99*4882a593Smuzhiyun *
100*4882a593Smuzhiyun * Returns 0 on success, error code otherwise
101*4882a593Smuzhiyun */
ima_store_template(struct ima_template_entry * entry,int violation,struct inode * inode,const unsigned char * filename,int pcr)102*4882a593Smuzhiyun int ima_store_template(struct ima_template_entry *entry,
103*4882a593Smuzhiyun int violation, struct inode *inode,
104*4882a593Smuzhiyun const unsigned char *filename, int pcr)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun static const char op[] = "add_template_measure";
107*4882a593Smuzhiyun static const char audit_cause[] = "hashing_error";
108*4882a593Smuzhiyun char *template_name = entry->template_desc->name;
109*4882a593Smuzhiyun int result;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if (!violation) {
112*4882a593Smuzhiyun result = ima_calc_field_array_hash(&entry->template_data[0],
113*4882a593Smuzhiyun entry);
114*4882a593Smuzhiyun if (result < 0) {
115*4882a593Smuzhiyun integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
116*4882a593Smuzhiyun template_name, op,
117*4882a593Smuzhiyun audit_cause, result, 0);
118*4882a593Smuzhiyun return result;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun entry->pcr = pcr;
122*4882a593Smuzhiyun result = ima_add_template_entry(entry, violation, op, inode, filename);
123*4882a593Smuzhiyun return result;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /*
127*4882a593Smuzhiyun * ima_add_violation - add violation to measurement list.
128*4882a593Smuzhiyun *
129*4882a593Smuzhiyun * Violations are flagged in the measurement list with zero hash values.
130*4882a593Smuzhiyun * By extending the PCR with 0xFF's instead of with zeroes, the PCR
131*4882a593Smuzhiyun * value is invalidated.
132*4882a593Smuzhiyun */
ima_add_violation(struct file * file,const unsigned char * filename,struct integrity_iint_cache * iint,const char * op,const char * cause)133*4882a593Smuzhiyun void ima_add_violation(struct file *file, const unsigned char *filename,
134*4882a593Smuzhiyun struct integrity_iint_cache *iint,
135*4882a593Smuzhiyun const char *op, const char *cause)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun struct ima_template_entry *entry;
138*4882a593Smuzhiyun struct inode *inode = file_inode(file);
139*4882a593Smuzhiyun struct ima_event_data event_data = { .iint = iint,
140*4882a593Smuzhiyun .file = file,
141*4882a593Smuzhiyun .filename = filename,
142*4882a593Smuzhiyun .violation = cause };
143*4882a593Smuzhiyun int violation = 1;
144*4882a593Smuzhiyun int result;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* can overflow, only indicator */
147*4882a593Smuzhiyun atomic_long_inc(&ima_htable.violations);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun result = ima_alloc_init_template(&event_data, &entry, NULL);
150*4882a593Smuzhiyun if (result < 0) {
151*4882a593Smuzhiyun result = -ENOMEM;
152*4882a593Smuzhiyun goto err_out;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun result = ima_store_template(entry, violation, inode,
155*4882a593Smuzhiyun filename, CONFIG_IMA_MEASURE_PCR_IDX);
156*4882a593Smuzhiyun if (result < 0)
157*4882a593Smuzhiyun ima_free_template_entry(entry);
158*4882a593Smuzhiyun err_out:
159*4882a593Smuzhiyun integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
160*4882a593Smuzhiyun op, cause, result, 0);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /**
164*4882a593Smuzhiyun * ima_get_action - appraise & measure decision based on policy.
165*4882a593Smuzhiyun * @inode: pointer to the inode associated with the object being validated
166*4882a593Smuzhiyun * @cred: pointer to credentials structure to validate
167*4882a593Smuzhiyun * @secid: secid of the task being validated
168*4882a593Smuzhiyun * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
169*4882a593Smuzhiyun * MAY_APPEND)
170*4882a593Smuzhiyun * @func: caller identifier
171*4882a593Smuzhiyun * @pcr: pointer filled in if matched measure policy sets pcr=
172*4882a593Smuzhiyun * @template_desc: pointer filled in if matched measure policy sets template=
173*4882a593Smuzhiyun * @keyring: keyring name used to determine the action
174*4882a593Smuzhiyun *
175*4882a593Smuzhiyun * The policy is defined in terms of keypairs:
176*4882a593Smuzhiyun * subj=, obj=, type=, func=, mask=, fsmagic=
177*4882a593Smuzhiyun * subj,obj, and type: are LSM specific.
178*4882a593Smuzhiyun * func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
179*4882a593Smuzhiyun * | KEXEC_CMDLINE | KEY_CHECK
180*4882a593Smuzhiyun * mask: contains the permission mask
181*4882a593Smuzhiyun * fsmagic: hex value
182*4882a593Smuzhiyun *
183*4882a593Smuzhiyun * Returns IMA_MEASURE, IMA_APPRAISE mask.
184*4882a593Smuzhiyun *
185*4882a593Smuzhiyun */
ima_get_action(struct inode * inode,const struct cred * cred,u32 secid,int mask,enum ima_hooks func,int * pcr,struct ima_template_desc ** template_desc,const char * keyring)186*4882a593Smuzhiyun int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
187*4882a593Smuzhiyun int mask, enum ima_hooks func, int *pcr,
188*4882a593Smuzhiyun struct ima_template_desc **template_desc,
189*4882a593Smuzhiyun const char *keyring)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun flags &= ima_policy_flag;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun return ima_match_policy(inode, cred, secid, func, mask, flags, pcr,
196*4882a593Smuzhiyun template_desc, keyring);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /*
200*4882a593Smuzhiyun * ima_collect_measurement - collect file measurement
201*4882a593Smuzhiyun *
202*4882a593Smuzhiyun * Calculate the file hash, if it doesn't already exist,
203*4882a593Smuzhiyun * storing the measurement and i_version in the iint.
204*4882a593Smuzhiyun *
205*4882a593Smuzhiyun * Must be called with iint->mutex held.
206*4882a593Smuzhiyun *
207*4882a593Smuzhiyun * Return 0 on success, error code otherwise
208*4882a593Smuzhiyun */
ima_collect_measurement(struct integrity_iint_cache * iint,struct file * file,void * buf,loff_t size,enum hash_algo algo,struct modsig * modsig)209*4882a593Smuzhiyun int ima_collect_measurement(struct integrity_iint_cache *iint,
210*4882a593Smuzhiyun struct file *file, void *buf, loff_t size,
211*4882a593Smuzhiyun enum hash_algo algo, struct modsig *modsig)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun const char *audit_cause = "failed";
214*4882a593Smuzhiyun struct inode *inode = file_inode(file);
215*4882a593Smuzhiyun const char *filename = file->f_path.dentry->d_name.name;
216*4882a593Smuzhiyun int result = 0;
217*4882a593Smuzhiyun int length;
218*4882a593Smuzhiyun void *tmpbuf;
219*4882a593Smuzhiyun u64 i_version;
220*4882a593Smuzhiyun struct {
221*4882a593Smuzhiyun struct ima_digest_data hdr;
222*4882a593Smuzhiyun char digest[IMA_MAX_DIGEST_SIZE];
223*4882a593Smuzhiyun } hash;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /*
226*4882a593Smuzhiyun * Always collect the modsig, because IMA might have already collected
227*4882a593Smuzhiyun * the file digest without collecting the modsig in a previous
228*4882a593Smuzhiyun * measurement rule.
229*4882a593Smuzhiyun */
230*4882a593Smuzhiyun if (modsig)
231*4882a593Smuzhiyun ima_collect_modsig(modsig, buf, size);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (iint->flags & IMA_COLLECTED)
234*4882a593Smuzhiyun goto out;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /*
237*4882a593Smuzhiyun * Dectecting file change is based on i_version. On filesystems
238*4882a593Smuzhiyun * which do not support i_version, support is limited to an initial
239*4882a593Smuzhiyun * measurement/appraisal/audit.
240*4882a593Smuzhiyun */
241*4882a593Smuzhiyun i_version = inode_query_iversion(inode);
242*4882a593Smuzhiyun hash.hdr.algo = algo;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun /* Initialize hash digest to 0's in case of failure */
245*4882a593Smuzhiyun memset(&hash.digest, 0, sizeof(hash.digest));
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun if (buf)
248*4882a593Smuzhiyun result = ima_calc_buffer_hash(buf, size, &hash.hdr);
249*4882a593Smuzhiyun else
250*4882a593Smuzhiyun result = ima_calc_file_hash(file, &hash.hdr);
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun if (result && result != -EBADF && result != -EINVAL)
253*4882a593Smuzhiyun goto out;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun length = sizeof(hash.hdr) + hash.hdr.length;
256*4882a593Smuzhiyun tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS);
257*4882a593Smuzhiyun if (!tmpbuf) {
258*4882a593Smuzhiyun result = -ENOMEM;
259*4882a593Smuzhiyun goto out;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun iint->ima_hash = tmpbuf;
263*4882a593Smuzhiyun memcpy(iint->ima_hash, &hash, length);
264*4882a593Smuzhiyun iint->version = i_version;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* Possibly temporary failure due to type of read (eg. O_DIRECT) */
267*4882a593Smuzhiyun if (!result)
268*4882a593Smuzhiyun iint->flags |= IMA_COLLECTED;
269*4882a593Smuzhiyun out:
270*4882a593Smuzhiyun if (result) {
271*4882a593Smuzhiyun if (file->f_flags & O_DIRECT)
272*4882a593Smuzhiyun audit_cause = "failed(directio)";
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
275*4882a593Smuzhiyun filename, "collect_data", audit_cause,
276*4882a593Smuzhiyun result, 0);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun return result;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun /*
282*4882a593Smuzhiyun * ima_store_measurement - store file measurement
283*4882a593Smuzhiyun *
284*4882a593Smuzhiyun * Create an "ima" template and then store the template by calling
285*4882a593Smuzhiyun * ima_store_template.
286*4882a593Smuzhiyun *
287*4882a593Smuzhiyun * We only get here if the inode has not already been measured,
288*4882a593Smuzhiyun * but the measurement could already exist:
289*4882a593Smuzhiyun * - multiple copies of the same file on either the same or
290*4882a593Smuzhiyun * different filesystems.
291*4882a593Smuzhiyun * - the inode was previously flushed as well as the iint info,
292*4882a593Smuzhiyun * containing the hashing info.
293*4882a593Smuzhiyun *
294*4882a593Smuzhiyun * Must be called with iint->mutex held.
295*4882a593Smuzhiyun */
ima_store_measurement(struct integrity_iint_cache * iint,struct file * file,const unsigned char * filename,struct evm_ima_xattr_data * xattr_value,int xattr_len,const struct modsig * modsig,int pcr,struct ima_template_desc * template_desc)296*4882a593Smuzhiyun void ima_store_measurement(struct integrity_iint_cache *iint,
297*4882a593Smuzhiyun struct file *file, const unsigned char *filename,
298*4882a593Smuzhiyun struct evm_ima_xattr_data *xattr_value,
299*4882a593Smuzhiyun int xattr_len, const struct modsig *modsig, int pcr,
300*4882a593Smuzhiyun struct ima_template_desc *template_desc)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun static const char op[] = "add_template_measure";
303*4882a593Smuzhiyun static const char audit_cause[] = "ENOMEM";
304*4882a593Smuzhiyun int result = -ENOMEM;
305*4882a593Smuzhiyun struct inode *inode = file_inode(file);
306*4882a593Smuzhiyun struct ima_template_entry *entry;
307*4882a593Smuzhiyun struct ima_event_data event_data = { .iint = iint,
308*4882a593Smuzhiyun .file = file,
309*4882a593Smuzhiyun .filename = filename,
310*4882a593Smuzhiyun .xattr_value = xattr_value,
311*4882a593Smuzhiyun .xattr_len = xattr_len,
312*4882a593Smuzhiyun .modsig = modsig };
313*4882a593Smuzhiyun int violation = 0;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun /*
316*4882a593Smuzhiyun * We still need to store the measurement in the case of MODSIG because
317*4882a593Smuzhiyun * we only have its contents to put in the list at the time of
318*4882a593Smuzhiyun * appraisal, but a file measurement from earlier might already exist in
319*4882a593Smuzhiyun * the measurement list.
320*4882a593Smuzhiyun */
321*4882a593Smuzhiyun if (iint->measured_pcrs & (0x1 << pcr) && !modsig)
322*4882a593Smuzhiyun return;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun result = ima_alloc_init_template(&event_data, &entry, template_desc);
325*4882a593Smuzhiyun if (result < 0) {
326*4882a593Smuzhiyun integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
327*4882a593Smuzhiyun op, audit_cause, result, 0);
328*4882a593Smuzhiyun return;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun result = ima_store_template(entry, violation, inode, filename, pcr);
332*4882a593Smuzhiyun if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) {
333*4882a593Smuzhiyun iint->flags |= IMA_MEASURED;
334*4882a593Smuzhiyun iint->measured_pcrs |= (0x1 << pcr);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun if (result < 0)
337*4882a593Smuzhiyun ima_free_template_entry(entry);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
ima_audit_measurement(struct integrity_iint_cache * iint,const unsigned char * filename)340*4882a593Smuzhiyun void ima_audit_measurement(struct integrity_iint_cache *iint,
341*4882a593Smuzhiyun const unsigned char *filename)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun struct audit_buffer *ab;
344*4882a593Smuzhiyun char *hash;
345*4882a593Smuzhiyun const char *algo_name = hash_algo_name[iint->ima_hash->algo];
346*4882a593Smuzhiyun int i;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun if (iint->flags & IMA_AUDITED)
349*4882a593Smuzhiyun return;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun hash = kzalloc((iint->ima_hash->length * 2) + 1, GFP_KERNEL);
352*4882a593Smuzhiyun if (!hash)
353*4882a593Smuzhiyun return;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun for (i = 0; i < iint->ima_hash->length; i++)
356*4882a593Smuzhiyun hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
357*4882a593Smuzhiyun hash[i * 2] = '\0';
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun ab = audit_log_start(audit_context(), GFP_KERNEL,
360*4882a593Smuzhiyun AUDIT_INTEGRITY_RULE);
361*4882a593Smuzhiyun if (!ab)
362*4882a593Smuzhiyun goto out;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun audit_log_format(ab, "file=");
365*4882a593Smuzhiyun audit_log_untrustedstring(ab, filename);
366*4882a593Smuzhiyun audit_log_format(ab, " hash=\"%s:%s\"", algo_name, hash);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun audit_log_task_info(ab);
369*4882a593Smuzhiyun audit_log_end(ab);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun iint->flags |= IMA_AUDITED;
372*4882a593Smuzhiyun out:
373*4882a593Smuzhiyun kfree(hash);
374*4882a593Smuzhiyun return;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun /*
378*4882a593Smuzhiyun * ima_d_path - return a pointer to the full pathname
379*4882a593Smuzhiyun *
380*4882a593Smuzhiyun * Attempt to return a pointer to the full pathname for use in the
381*4882a593Smuzhiyun * IMA measurement list, IMA audit records, and auditing logs.
382*4882a593Smuzhiyun *
383*4882a593Smuzhiyun * On failure, return a pointer to a copy of the filename, not dname.
384*4882a593Smuzhiyun * Returning a pointer to dname, could result in using the pointer
385*4882a593Smuzhiyun * after the memory has been freed.
386*4882a593Smuzhiyun */
ima_d_path(const struct path * path,char ** pathbuf,char * namebuf)387*4882a593Smuzhiyun const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun char *pathname = NULL;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun *pathbuf = __getname();
392*4882a593Smuzhiyun if (*pathbuf) {
393*4882a593Smuzhiyun pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
394*4882a593Smuzhiyun if (IS_ERR(pathname)) {
395*4882a593Smuzhiyun __putname(*pathbuf);
396*4882a593Smuzhiyun *pathbuf = NULL;
397*4882a593Smuzhiyun pathname = NULL;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (!pathname) {
402*4882a593Smuzhiyun strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX);
403*4882a593Smuzhiyun pathname = namebuf;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun return pathname;
407*4882a593Smuzhiyun }
408