[PATCH] fix faulty inode data collection for open() with O_CREAT

When the specified path is an existing file or when it is a symlink, audit
collects the wrong inode number, which causes it to miss the open() event.
Adding a second hook to the open() path fixes this.

Also add audit_copy_inode() to consolidate some code.

Signed-off-by: Amy Griffis <amy.griffis@hp.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by Amy Griffis and committed by Al Viro 3e2efce0 46f5960f

+50 -22
+2
fs/namei.c
··· 1659 1659 * It already exists. 1660 1660 */ 1661 1661 mutex_unlock(&dir->d_inode->i_mutex); 1662 + audit_inode_update(path.dentry->d_inode); 1662 1663 1663 1664 error = -EEXIST; 1664 1665 if (flag & O_EXCL) ··· 1670 1669 if (flag & O_NOFOLLOW) 1671 1670 goto exit_dput; 1672 1671 } 1672 + 1673 1673 error = -ENOENT; 1674 1674 if (!path.dentry->d_inode) 1675 1675 goto exit_dput;
+7
include/linux/audit.h
··· 328 328 extern void __audit_inode(const char *name, const struct inode *inode); 329 329 extern void __audit_inode_child(const char *dname, const struct inode *inode, 330 330 unsigned long pino); 331 + extern void __audit_inode_update(const struct inode *inode); 331 332 static inline void audit_getname(const char *name) 332 333 { 333 334 if (unlikely(current->audit_context)) ··· 343 342 unsigned long pino) { 344 343 if (unlikely(current->audit_context)) 345 344 __audit_inode_child(dname, inode, pino); 345 + } 346 + static inline void audit_inode_update(const struct inode *inode) { 347 + if (unlikely(current->audit_context)) 348 + __audit_inode_update(inode); 346 349 } 347 350 348 351 /* Private API (for audit.c only) */ ··· 419 414 #define audit_putname(n) do { ; } while (0) 420 415 #define __audit_inode(n,i) do { ; } while (0) 421 416 #define __audit_inode_child(d,i,p) do { ; } while (0) 417 + #define __audit_inode_update(i) do { ; } while (0) 422 418 #define audit_inode(n,i) do { ; } while (0) 423 419 #define audit_inode_child(d,i,p) do { ; } while (0) 420 + #define audit_inode_update(i) do { ; } while (0) 424 421 #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) 425 422 #define audit_get_loginuid(c) ({ -1; }) 426 423 #define audit_ipc_obj(i) ({ 0; })
+41 -22
kernel/auditsc.c
··· 1199 1199 #endif 1200 1200 } 1201 1201 1202 - static void audit_inode_context(int idx, const struct inode *inode) 1202 + /* Copy inode data into an audit_names. */ 1203 + static void audit_copy_inode(struct audit_names *name, const struct inode *inode) 1203 1204 { 1204 - struct audit_context *context = current->audit_context; 1205 - 1206 - selinux_get_inode_sid(inode, &context->names[idx].osid); 1205 + name->ino = inode->i_ino; 1206 + name->dev = inode->i_sb->s_dev; 1207 + name->mode = inode->i_mode; 1208 + name->uid = inode->i_uid; 1209 + name->gid = inode->i_gid; 1210 + name->rdev = inode->i_rdev; 1211 + selinux_get_inode_sid(inode, &name->osid); 1207 1212 } 1208 - 1209 1213 1210 1214 /** 1211 1215 * audit_inode - store the inode and device from a lookup ··· 1244 1240 ++context->ino_count; 1245 1241 #endif 1246 1242 } 1247 - context->names[idx].ino = inode->i_ino; 1248 - context->names[idx].dev = inode->i_sb->s_dev; 1249 - context->names[idx].mode = inode->i_mode; 1250 - context->names[idx].uid = inode->i_uid; 1251 - context->names[idx].gid = inode->i_gid; 1252 - context->names[idx].rdev = inode->i_rdev; 1253 - audit_inode_context(idx, inode); 1243 + audit_copy_inode(&context->names[idx], inode); 1254 1244 } 1255 1245 1256 1246 /** ··· 1300 1302 context->names[idx].name_len = AUDIT_NAME_FULL; 1301 1303 context->names[idx].name_put = 0; /* don't call __putname() */ 1302 1304 1303 - if (inode) { 1304 - context->names[idx].ino = inode->i_ino; 1305 - context->names[idx].dev = inode->i_sb->s_dev; 1306 - context->names[idx].mode = inode->i_mode; 1307 - context->names[idx].uid = inode->i_uid; 1308 - context->names[idx].gid = inode->i_gid; 1309 - context->names[idx].rdev = inode->i_rdev; 1310 - audit_inode_context(idx, inode); 1311 - } else 1312 - context->names[idx].ino = (unsigned long)-1; 1305 + if (!inode) 1306 + context->names[idx].ino = (unsigned long)-1; 1307 + else 1308 + audit_copy_inode(&context->names[idx], inode); 1309 + } 1310 + 1311 + /** 1312 + * audit_inode_update - update inode info for last collected name 1313 + * @inode: inode being audited 1314 + * 1315 + * When open() is called on an existing object with the O_CREAT flag, the inode 1316 + * data audit initially collects is incorrect. This additional hook ensures 1317 + * audit has the inode data for the actual object to be opened. 1318 + */ 1319 + void __audit_inode_update(const struct inode *inode) 1320 + { 1321 + struct audit_context *context = current->audit_context; 1322 + int idx; 1323 + 1324 + if (!context->in_syscall || !inode) 1325 + return; 1326 + 1327 + if (context->name_count == 0) { 1328 + context->name_count++; 1329 + #if AUDIT_DEBUG 1330 + context->ino_count++; 1331 + #endif 1332 + } 1333 + idx = context->name_count - 1; 1334 + 1335 + audit_copy_inode(&context->names[idx], inode); 1313 1336 } 1314 1337 1315 1338 /**