Commit 05d1a717 authored by Mimi Zohar's avatar Mimi Zohar

ima: add support for creating files using the mknodat syscall

Commit 3034a146 "ima: pass 'opened' flag to identify newly created files"
stopped identifying empty files as new files.  However new empty files
can be created using the mknodat syscall.  On systems with IMA-appraisal
enabled, these empty files are not labeled with security.ima extended
attributes properly, preventing them from subsequently being opened in
order to write the file data contents.  This patch defines a new hook
named ima_post_path_mknod() to mark these empty files, created using
mknodat, as new in order to allow the file data contents to be written.

In addition, files with security.ima xattrs containing a file signature
are considered "immutable" and can not be modified.  The file contents
need to be written, before signing the file.  This patch relaxes this
requirement for new files, allowing the file signature to be written
before the file contents.

Changelog:
- defer identifying files with signatures stored as security.ima
  (based on Dmitry Rozhkov's comments)
- removing tests (eg. dentry, dentry->d_inode, inode->i_size == 0)
  (based on Al's review)
Signed-off-by: default avatarMimi Zohar <zohar@linux.vnet.ibm.com>
Cc: Al Viro <<viro@zeniv.linux.org.uk>
Tested-by: default avatarDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
parent 42a4c603
...@@ -3608,6 +3608,8 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, ...@@ -3608,6 +3608,8 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
switch (mode & S_IFMT) { switch (mode & S_IFMT) {
case 0: case S_IFREG: case 0: case S_IFREG:
error = vfs_create(path.dentry->d_inode,dentry,mode,true); error = vfs_create(path.dentry->d_inode,dentry,mode,true);
if (!error)
ima_post_path_mknod(dentry);
break; break;
case S_IFCHR: case S_IFBLK: case S_IFCHR: case S_IFBLK:
error = vfs_mknod(path.dentry->d_inode,dentry,mode, error = vfs_mknod(path.dentry->d_inode,dentry,mode,
......
...@@ -21,6 +21,7 @@ extern int ima_file_mmap(struct file *file, unsigned long prot); ...@@ -21,6 +21,7 @@ extern int ima_file_mmap(struct file *file, unsigned long prot);
extern int ima_read_file(struct file *file, enum kernel_read_file_id id); extern int ima_read_file(struct file *file, enum kernel_read_file_id id);
extern int ima_post_read_file(struct file *file, void *buf, loff_t size, extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id id); enum kernel_read_file_id id);
extern void ima_post_path_mknod(struct dentry *dentry);
#else #else
static inline int ima_bprm_check(struct linux_binprm *bprm) static inline int ima_bprm_check(struct linux_binprm *bprm)
...@@ -54,6 +55,11 @@ static inline int ima_post_read_file(struct file *file, void *buf, loff_t size, ...@@ -54,6 +55,11 @@ static inline int ima_post_read_file(struct file *file, void *buf, loff_t size,
return 0; return 0;
} }
static inline void ima_post_path_mknod(struct dentry *dentry)
{
return;
}
#endif /* CONFIG_IMA */ #endif /* CONFIG_IMA */
#ifdef CONFIG_IMA_APPRAISE #ifdef CONFIG_IMA_APPRAISE
......
...@@ -275,6 +275,11 @@ int ima_appraise_measurement(enum ima_hooks func, ...@@ -275,6 +275,11 @@ int ima_appraise_measurement(enum ima_hooks func,
xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
if (!ima_fix_xattr(dentry, iint)) if (!ima_fix_xattr(dentry, iint))
status = INTEGRITY_PASS; status = INTEGRITY_PASS;
} else if ((inode->i_size == 0) &&
(iint->flags & IMA_NEW_FILE) &&
(xattr_value &&
xattr_value->type == EVM_IMA_XATTR_DIGSIG)) {
status = INTEGRITY_PASS;
} }
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
op, cause, rc, 0); op, cause, rc, 0);
......
...@@ -246,7 +246,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size, ...@@ -246,7 +246,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
ima_audit_measurement(iint, pathname); ima_audit_measurement(iint, pathname);
out_digsig: out_digsig:
if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) &&
!(iint->flags & IMA_NEW_FILE))
rc = -EACCES; rc = -EACCES;
kfree(xattr_value); kfree(xattr_value);
out_free: out_free:
...@@ -315,6 +316,28 @@ int ima_file_check(struct file *file, int mask, int opened) ...@@ -315,6 +316,28 @@ int ima_file_check(struct file *file, int mask, int opened)
} }
EXPORT_SYMBOL_GPL(ima_file_check); EXPORT_SYMBOL_GPL(ima_file_check);
/**
* ima_post_path_mknod - mark as a new inode
* @dentry: newly created dentry
*
* Mark files created via the mknodat syscall as new, so that the
* file data can be written later.
*/
void ima_post_path_mknod(struct dentry *dentry)
{
struct integrity_iint_cache *iint;
struct inode *inode = dentry->d_inode;
int must_appraise;
must_appraise = ima_must_appraise(inode, MAY_ACCESS, FILE_CHECK);
if (!must_appraise)
return;
iint = integrity_inode_get(inode);
if (iint)
iint->flags |= IMA_NEW_FILE;
}
/** /**
* ima_read_file - pre-measure/appraise hook decision based on policy * ima_read_file - pre-measure/appraise hook decision based on policy
* @file: pointer to the file to be measured/appraised/audit * @file: pointer to the file to be measured/appraised/audit
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment