Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ima: fix ima_d_path() possible race with rename

On failure to return a pathname from ima_d_path(), a pointer to
dname is returned, which is subsequently used in the IMA measurement
list, the IMA audit records, and other audit logging. Saving the
pointer to dname for later use has the potential to race with rename.

Intead of returning a pointer to dname on failure, this patch returns
a pointer to a copy of the filename.

Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Cc: stable@vger.kernel.org

+24 -6
+1 -1
security/integrity/ima/ima.h
··· 204 204 struct inode *inode, 205 205 const unsigned char *filename, int pcr); 206 206 void ima_free_template_entry(struct ima_template_entry *entry); 207 - const char *ima_d_path(const struct path *path, char **pathbuf); 207 + const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); 208 208 209 209 /* IMA policy related functions */ 210 210 int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
+18 -2
security/integrity/ima/ima_api.c
··· 318 318 iint->flags |= IMA_AUDITED; 319 319 } 320 320 321 - const char *ima_d_path(const struct path *path, char **pathbuf) 321 + /* 322 + * ima_d_path - return a pointer to the full pathname 323 + * 324 + * Attempt to return a pointer to the full pathname for use in the 325 + * IMA measurement list, IMA audit records, and auditing logs. 326 + * 327 + * On failure, return a pointer to a copy of the filename, not dname. 328 + * Returning a pointer to dname, could result in using the pointer 329 + * after the memory has been freed. 330 + */ 331 + const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf) 322 332 { 323 333 char *pathname = NULL; 324 334 ··· 341 331 pathname = NULL; 342 332 } 343 333 } 344 - return pathname ?: (const char *)path->dentry->d_name.name; 334 + 335 + if (!pathname) { 336 + strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX); 337 + pathname = namebuf; 338 + } 339 + 340 + return pathname; 345 341 }
+5 -3
security/integrity/ima/ima_main.c
··· 83 83 const char **pathname) 84 84 { 85 85 struct inode *inode = file_inode(file); 86 + char filename[NAME_MAX]; 86 87 fmode_t mode = file->f_mode; 87 88 bool send_tomtou = false, send_writers = false; 88 89 ··· 103 102 if (!send_tomtou && !send_writers) 104 103 return; 105 104 106 - *pathname = ima_d_path(&file->f_path, pathbuf); 105 + *pathname = ima_d_path(&file->f_path, pathbuf, filename); 107 106 108 107 if (send_tomtou) 109 108 ima_add_violation(file, *pathname, iint, ··· 162 161 struct integrity_iint_cache *iint = NULL; 163 162 struct ima_template_desc *template_desc; 164 163 char *pathbuf = NULL; 164 + char filename[NAME_MAX]; 165 165 const char *pathname = NULL; 166 166 int rc = -ENOMEM, action, must_appraise; 167 167 int pcr = CONFIG_IMA_MEASURE_PCR_IDX; ··· 241 239 goto out_digsig; 242 240 } 243 241 244 - if (!pathname) /* ima_rdwr_violation possibly pre-fetched */ 245 - pathname = ima_d_path(&file->f_path, &pathbuf); 242 + if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ 243 + pathname = ima_d_path(&file->f_path, &pathbuf, filename); 246 244 247 245 if (action & IMA_MEASURE) 248 246 ima_store_measurement(iint, file, pathname,