===================================================================
@@ -401,6 +401,17 @@
* @inode contains a pointer to the inode.
* @secid contains a pointer to the location where result will be saved.
* In case of failure, @secid will be set to zero.
+ * @inode_copy_up:
+ * A file is about to be copied up from lower layer to upper layer of
+ * overlay filesystem. Prepare a new set of creds and set file creation
+ * secid in such a way so that copied up file gets the appropriate
+ * label. Switch to this newly prepared creds and return old creds. This
+ * returns with only one reference to newly prepared creds. So as soon
+ * as caller calls revert_cred(old_creds), creds allocated by this hook
+ * should be freed.
+ * @src indicates the union dentry of file that is being copied up.
+ * @old indicates the pointer to old_cred returned to caller.
+ * Returns 0 on success or a negative error code on error.
*
* Security hooks for file operations
*
@@ -1425,6 +1436,7 @@ union security_list_options {
int (*inode_listsecurity)(struct inode *inode, char *buffer,
size_t buffer_size);
void (*inode_getsecid)(struct inode *inode, u32 *secid);
+ int (*inode_copy_up) (struct dentry *src, const struct cred **old);
int (*file_permission)(struct file *file, int mask);
int (*file_alloc_security)(struct file *file);
@@ -1696,6 +1708,7 @@ struct security_hook_heads {
struct list_head inode_setsecurity;
struct list_head inode_listsecurity;
struct list_head inode_getsecid;
+ struct list_head inode_copy_up;
struct list_head file_permission;
struct list_head file_alloc_security;
struct list_head file_free_security;
===================================================================
@@ -282,6 +282,7 @@ int security_inode_getsecurity(struct in
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
void security_inode_getsecid(struct inode *inode, u32 *secid);
+int security_inode_copy_up(struct dentry *src, const struct cred **old);
int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
void security_file_free(struct file *file);
@@ -758,6 +759,12 @@ static inline void security_inode_getsec
*secid = 0;
}
+static inline int security_inode_copy_up(struct dentry *src,
+ const struct cred **old)
+{
+ return 0;
+}
+
static inline int security_file_permission(struct file *file, int mask)
{
return 0;
===================================================================
@@ -727,6 +727,12 @@ void security_inode_getsecid(struct inod
call_void_hook(inode_getsecid, inode, secid);
}
+int security_inode_copy_up(struct dentry *src, const struct cred **old)
+{
+ return call_int_hook(inode_copy_up, 0, src, old);
+}
+EXPORT_SYMBOL(security_inode_copy_up);
+
int security_file_permission(struct file *file, int mask)
{
int ret;
@@ -1663,6 +1669,8 @@ struct security_hook_heads security_hook
LIST_HEAD_INIT(security_hook_heads.inode_listsecurity),
.inode_getsecid =
LIST_HEAD_INIT(security_hook_heads.inode_getsecid),
+ .inode_copy_up =
+ LIST_HEAD_INIT(security_hook_heads.inode_copy_up),
.file_permission =
LIST_HEAD_INIT(security_hook_heads.file_permission),
.file_alloc_security =
===================================================================
@@ -246,6 +246,7 @@ static int ovl_copy_up_locked(struct den
struct dentry *upper = NULL;
umode_t mode = stat->mode;
int err;
+ const struct cred *old_creds = NULL;
newdentry = ovl_lookup_temp(workdir, dentry);
err = PTR_ERR(newdentry);
@@ -258,10 +259,17 @@ static int ovl_copy_up_locked(struct den
if (IS_ERR(upper))
goto out1;
+ err = security_inode_copy_up(dentry, &old_creds);
+ if (err < 0)
+ goto out2;
+
/* Can't properly set mode on creation because of the umask */
stat->mode &= S_IFMT;
err = ovl_create_real(wdir, newdentry, stat, link, NULL, true);
stat->mode = mode;
+ if (old_creds)
+ revert_creds(old_creds);
+
if (err)
goto out2;
===================================================================
@@ -3270,6 +3270,32 @@ static void selinux_inode_getsecid(struc
*secid = isec->sid;
}
+static int selinux_inode_copy_up(struct dentry *src, const struct cred **old)
+{
+ u32 sid;
+ struct cred *new_creds;
+ struct task_security_struct *tsec;
+
+ new_creds = prepare_creds();
+ if (!new_creds)
+ return -ENOMEM;
+
+ /* Get label from overlay inode and set it in create_sid */
+ selinux_inode_getsecid(d_inode(src), &sid);
+ tsec = new_creds->security;
+ tsec->create_sid = sid;
+ *old = override_creds(new_creds);
+
+ /*
+ * At this point of time we have 2 refs on new_creds. One by
+ * prepare_creds and other by override_creds. Drop one reference
+ * so that as soon as caller calls revert_creds(old), this cred
+ * will be freed.
+ */
+ put_cred(new_creds);
+ return 0;
+}
+
/* file security operations */
static int selinux_revalidate_file_permission(struct file *file, int mask)
@@ -6056,6 +6082,7 @@ static struct security_hook_list selinux
LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
+ LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),