// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Copyright (C) 2011 Novell Inc.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/fileattr.h>
#include <linux/splice.h>
#include <linux/xattr.h>
#include <linux/security.h>
#include <linux/uaccess.h>
#include <linux/sched/signal.h>
#include <linux/cred.h>
#include <linux/namei.h>
#include <linux/fdtable.h>
#include <linux/ratelimit.h>
#include <linux/exportfs.h>
#include "overlayfs.h"
#define OVL_COPY_UP_CHUNK_SIZE (1 << 20)
static int ovl_ccup_set(const char *buf, const struct kernel_param *param)
{
pr_warn("\"check_copy_up\" module option is obsolete\n");
return 0;
}
static int ovl_ccup_get(char *buf, const struct kernel_param *param)
{
return sprintf(buf, "N\n");
}
module_param_call(check_copy_up, ovl_ccup_set, ovl_ccup_get, NULL, 0644);
MODULE_PARM_DESC(check_copy_up, "Obsolete; does nothing");
static bool ovl_must_copy_xattr(const char *name)
{
return !strcmp(name, XATTR_POSIX_ACL_ACCESS) ||
!strcmp(name, XATTR_POSIX_ACL_DEFAULT) ||
!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
}
static int ovl_copy_acl(struct ovl_fs *ofs, const struct path *path,
struct dentry *dentry, const char *acl_name)
{
int err;
struct posix_acl *clone, *real_acl = NULL;
real_acl = ovl_get_acl_path(path, acl_name, false);
if (!real_acl)
return 0;
if (IS_ERR(real_acl)) {
err = PTR_ERR(real_acl);
if (err == -ENODATA || err == -EOPNOTSUPP)
return 0;
return err;
}
clone = posix_acl_clone(real_acl, GFP_KERNEL);
posix_acl_release(real_acl); /* release original acl */
if (!clone)
return -ENOMEM;
err = ovl_do_set_acl(ofs, dentry, acl_name, clone);
/* release cloned acl */
posix_acl_release(clone);
return err;
}
int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct dentry *new)
{
struct dentry *old = oldpath->dentry;
ssize_t list_size, size, value_size = 0;
char *buf, *name, *value = NULL;
int error = 0;
size_t slen;
if (!old->d_inode->i_op->listxattr || !new->d_inode->i_op->listxattr)
return 0;
list_size = vfs_listxattr(old, NULL, 0);
if (list_size <= 0) {
if (list_size == -EOPNOTSUPP)
return 0;
return list_size;
}
buf = kvzalloc(list_size, GFP_KERNEL);