Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (39 commits) [PATCH] fix RLIM_NOFILE handling [PATCH] get rid of corner case in dup3() entirely [PATCH] remove remaining namei_{32,64}.h crap [PATCH] get rid of indirect users of namei.h [PATCH] get rid of __user_path_lookup_open [PATCH] f_count may wrap around [PATCH] dup3 fix [PATCH] don't pass nameidata to __ncp_lookup_validate() [PATCH] don't pass nameidata to gfs2_lookupi() [PATCH] new (local) helper: user_path_parent() [PATCH] sanitize __user_walk_fd() et.al. [PATCH] preparation to __user_walk_fd cleanup [PATCH] kill nameidata passing to permission(), rename to inode_permission() [PATCH] take noexec checks to very few callers that care Re: [PATCH 3/6] vfs: open_exec cleanup [patch 4/4] vfs: immutable inode checking cleanup [patch 3/4] fat: dont call notify_change [patch 2/4] vfs: utimes cleanup [patch 1/4] vfs: utimes: move owner check into inode_change_ok() [PATCH] vfs: use kstrdup() and check failing allocation ...
This commit is contained in:
Коммит
4836e30078
|
@ -253,15 +253,15 @@ do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer,
|
|||
}
|
||||
|
||||
asmlinkage int
|
||||
osf_statfs(char __user *path, struct osf_statfs __user *buffer, unsigned long bufsiz)
|
||||
osf_statfs(char __user *pathname, struct osf_statfs __user *buffer, unsigned long bufsiz)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int retval;
|
||||
|
||||
retval = user_path_walk(path, &nd);
|
||||
retval = user_path(pathname, &path);
|
||||
if (!retval) {
|
||||
retval = do_osf_statfs(nd.path.dentry, buffer, bufsiz);
|
||||
path_put(&nd.path);
|
||||
retval = do_osf_statfs(path.dentry, buffer, bufsiz);
|
||||
path_put(&path);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -210,19 +210,19 @@ static int vfs_statfs_hpux(struct dentry *dentry, struct hpux_statfs *buf)
|
|||
}
|
||||
|
||||
/* hpux statfs */
|
||||
asmlinkage long hpux_statfs(const char __user *path,
|
||||
asmlinkage long hpux_statfs(const char __user *pathname,
|
||||
struct hpux_statfs __user *buf)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (!error) {
|
||||
struct hpux_statfs tmp;
|
||||
error = vfs_statfs_hpux(nd.path.dentry, &tmp);
|
||||
error = vfs_statfs_hpux(path.dentry, &tmp);
|
||||
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
||||
error = -EFAULT;
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -581,12 +581,12 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
if (file == ppp->owner)
|
||||
ppp_shutdown_interface(ppp);
|
||||
}
|
||||
if (atomic_read(&file->f_count) <= 2) {
|
||||
if (atomic_long_read(&file->f_count) <= 2) {
|
||||
ppp_release(NULL, file);
|
||||
err = 0;
|
||||
} else
|
||||
printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n",
|
||||
atomic_read(&file->f_count));
|
||||
printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%ld\n",
|
||||
atomic_long_read(&file->f_count));
|
||||
unlock_kernel();
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -46,8 +46,6 @@ const struct inode_operations affs_file_inode_operations = {
|
|||
static int
|
||||
affs_file_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (atomic_read(&filp->f_count) != 1)
|
||||
return 0;
|
||||
pr_debug("AFFS: open(%lu,%d)\n",
|
||||
inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
|
||||
atomic_inc(&AFFS_I(inode)->i_opencnt);
|
||||
|
@ -57,8 +55,6 @@ affs_file_open(struct inode *inode, struct file *filp)
|
|||
static int
|
||||
affs_file_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (atomic_read(&filp->f_count) != 0)
|
||||
return 0;
|
||||
pr_debug("AFFS: release(%lu, %d)\n",
|
||||
inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
|
||||
|
||||
|
|
|
@ -469,8 +469,6 @@ extern bool afs_cm_incoming_call(struct afs_call *);
|
|||
extern const struct inode_operations afs_dir_inode_operations;
|
||||
extern const struct file_operations afs_dir_file_operations;
|
||||
|
||||
extern int afs_permission(struct inode *, int, struct nameidata *);
|
||||
|
||||
/*
|
||||
* file.c
|
||||
*/
|
||||
|
@ -605,7 +603,7 @@ extern void afs_clear_permits(struct afs_vnode *);
|
|||
extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
|
||||
extern void afs_zap_permits(struct rcu_head *);
|
||||
extern struct key *afs_request_key(struct afs_cell *);
|
||||
extern int afs_permission(struct inode *, int, struct nameidata *);
|
||||
extern int afs_permission(struct inode *, int);
|
||||
|
||||
/*
|
||||
* server.c
|
||||
|
|
|
@ -284,7 +284,7 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
|
|||
* - AFS ACLs are attached to directories only, and a file is controlled by its
|
||||
* parent directory's ACL
|
||||
*/
|
||||
int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
int afs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||
afs_access_t uninitialized_var(access);
|
||||
|
|
6
fs/aio.c
6
fs/aio.c
|
@ -512,8 +512,8 @@ static void aio_fput_routine(struct work_struct *data)
|
|||
*/
|
||||
static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
|
||||
{
|
||||
dprintk(KERN_DEBUG "aio_put(%p): f_count=%d\n",
|
||||
req, atomic_read(&req->ki_filp->f_count));
|
||||
dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n",
|
||||
req, atomic_long_read(&req->ki_filp->f_count));
|
||||
|
||||
assert_spin_locked(&ctx->ctx_lock);
|
||||
|
||||
|
@ -528,7 +528,7 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
|
|||
/* Must be done under the lock to serialise against cancellation.
|
||||
* Call this aio_fput as it duplicates fput via the fput_work.
|
||||
*/
|
||||
if (unlikely(atomic_dec_and_test(&req->ki_filp->f_count))) {
|
||||
if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) {
|
||||
get_ioctx(ctx);
|
||||
spin_lock(&fput_lock);
|
||||
list_add(&req->ki_list, &fput_head);
|
||||
|
|
|
@ -51,7 +51,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
|
|||
}
|
||||
|
||||
/* Check for setting the inode time. */
|
||||
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
|
||||
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
|
||||
if (!is_owner_or_cap(inode))
|
||||
goto error;
|
||||
}
|
||||
|
@ -108,6 +108,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
|
|||
struct timespec now;
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
|
||||
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
now = current_fs_time(inode->i_sb);
|
||||
|
||||
attr->ia_ctime = now;
|
||||
|
|
|
@ -243,8 +243,7 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_permission(struct inode *inode, int mask,
|
||||
struct nameidata *nd)
|
||||
static int bad_inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
|
|
@ -267,7 +267,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
static int cifs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
|
||||
|
|
|
@ -137,9 +137,11 @@ exit:
|
|||
}
|
||||
|
||||
|
||||
int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
int coda_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
|
||||
|
||||
if (!mask)
|
||||
return 0;
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
#include <linux/coda_psdev.h>
|
||||
|
||||
/* pioctl ops */
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask,
|
||||
struct nameidata *nd);
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask);
|
||||
static int coda_pioctl(struct inode * inode, struct file * filp,
|
||||
unsigned int cmd, unsigned long user_data);
|
||||
|
||||
|
@ -42,8 +41,7 @@ const struct file_operations coda_ioctl_operations = {
|
|||
};
|
||||
|
||||
/* the coda pioctl inode ops */
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask,
|
||||
struct nameidata *nd)
|
||||
static int coda_ioctl_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -51,7 +49,7 @@ static int coda_ioctl_permission(struct inode *inode, int mask,
|
|||
static int coda_pioctl(struct inode * inode, struct file * filp,
|
||||
unsigned int cmd, unsigned long user_data)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
struct PioctlData data;
|
||||
struct inode *target_inode = NULL;
|
||||
|
@ -66,21 +64,21 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
|
|||
* Look up the pathname. Note that the pathname is in
|
||||
* user memory, and namei takes care of this
|
||||
*/
|
||||
if ( data.follow ) {
|
||||
error = user_path_walk(data.path, &nd);
|
||||
if (data.follow) {
|
||||
error = user_path(data.path, &path);
|
||||
} else {
|
||||
error = user_path_walk_link(data.path, &nd);
|
||||
error = user_lpath(data.path, &path);
|
||||
}
|
||||
|
||||
if ( error ) {
|
||||
return error;
|
||||
} else {
|
||||
target_inode = nd.path.dentry->d_inode;
|
||||
target_inode = path.dentry->d_inode;
|
||||
}
|
||||
|
||||
/* return if it is not a Coda inode */
|
||||
if ( target_inode->i_sb != inode->i_sb ) {
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -89,7 +87,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
|
|||
|
||||
error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
|
||||
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
20
fs/compat.c
20
fs/compat.c
|
@ -234,18 +234,18 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
|
|||
* The following statfs calls are copies of code from fs/open.c and
|
||||
* should be checked against those from time to time
|
||||
*/
|
||||
asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs __user *buf)
|
||||
asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (!error) {
|
||||
struct kstatfs tmp;
|
||||
error = vfs_statfs(nd.path.dentry, &tmp);
|
||||
error = vfs_statfs(path.dentry, &tmp);
|
||||
if (!error)
|
||||
error = put_compat_statfs(buf, &tmp);
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -299,21 +299,21 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
|
|||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, struct compat_statfs64 __user *buf)
|
||||
asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
if (sz != sizeof(*buf))
|
||||
return -EINVAL;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (!error) {
|
||||
struct kstatfs tmp;
|
||||
error = vfs_statfs(nd.path.dentry, &tmp);
|
||||
error = vfs_statfs(path.dentry, &tmp);
|
||||
if (!error)
|
||||
error = put_compat_statfs64(buf, &tmp);
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -465,7 +465,6 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
struct dentry *lower_dir_dentry;
|
||||
umode_t mode;
|
||||
char *encoded_symname;
|
||||
int encoded_symlen;
|
||||
struct ecryptfs_crypt_stat *crypt_stat = NULL;
|
||||
|
@ -473,7 +472,6 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
dget(lower_dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
mode = S_IALLUGO;
|
||||
encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
|
||||
strlen(symname),
|
||||
&encoded_symname);
|
||||
|
@ -482,7 +480,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
goto out_lock;
|
||||
}
|
||||
rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
|
||||
encoded_symname, mode);
|
||||
encoded_symname);
|
||||
kfree(encoded_symname);
|
||||
if (rc || !lower_dentry->d_inode)
|
||||
goto out_lock;
|
||||
|
@ -830,22 +828,9 @@ out:
|
|||
}
|
||||
|
||||
static int
|
||||
ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
ecryptfs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (nd) {
|
||||
struct vfsmount *vfsmnt_save = nd->path.mnt;
|
||||
struct dentry *dentry_save = nd->path.dentry;
|
||||
|
||||
nd->path.mnt = ecryptfs_dentry_to_lower_mnt(nd->path.dentry);
|
||||
nd->path.dentry = ecryptfs_dentry_to_lower(nd->path.dentry);
|
||||
rc = permission(ecryptfs_inode_to_lower(inode), mask, nd);
|
||||
nd->path.mnt = vfsmnt_save;
|
||||
nd->path.dentry = dentry_save;
|
||||
} else
|
||||
rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL);
|
||||
return rc;
|
||||
return inode_permission(ecryptfs_inode_to_lower(inode), mask);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
77
fs/exec.c
77
fs/exec.c
|
@ -106,11 +106,17 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
|
|||
*/
|
||||
asmlinkage long sys_uselib(const char __user * library)
|
||||
{
|
||||
struct file * file;
|
||||
struct file *file;
|
||||
struct nameidata nd;
|
||||
int error;
|
||||
char *tmp = getname(library);
|
||||
int error = PTR_ERR(tmp);
|
||||
|
||||
error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);
|
||||
if (!IS_ERR(tmp)) {
|
||||
error = path_lookup_open(AT_FDCWD, tmp,
|
||||
LOOKUP_FOLLOW, &nd,
|
||||
FMODE_READ|FMODE_EXEC);
|
||||
putname(tmp);
|
||||
}
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
|
@ -118,7 +124,11 @@ asmlinkage long sys_uselib(const char __user * library)
|
|||
if (!S_ISREG(nd.path.dentry->d_inode->i_mode))
|
||||
goto exit;
|
||||
|
||||
error = vfs_permission(&nd, MAY_READ | MAY_EXEC);
|
||||
error = -EACCES;
|
||||
if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
|
||||
goto exit;
|
||||
|
||||
error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN);
|
||||
if (error)
|
||||
goto exit;
|
||||
|
||||
|
@ -656,38 +666,43 @@ EXPORT_SYMBOL(setup_arg_pages);
|
|||
struct file *open_exec(const char *name)
|
||||
{
|
||||
struct nameidata nd;
|
||||
int err;
|
||||
struct file *file;
|
||||
int err;
|
||||
|
||||
err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);
|
||||
file = ERR_PTR(err);
|
||||
err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd,
|
||||
FMODE_READ|FMODE_EXEC);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!err) {
|
||||
struct inode *inode = nd.path.dentry->d_inode;
|
||||
file = ERR_PTR(-EACCES);
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
int err = vfs_permission(&nd, MAY_EXEC);
|
||||
file = ERR_PTR(err);
|
||||
if (!err) {
|
||||
file = nameidata_to_filp(&nd,
|
||||
O_RDONLY|O_LARGEFILE);
|
||||
if (!IS_ERR(file)) {
|
||||
err = deny_write_access(file);
|
||||
if (err) {
|
||||
fput(file);
|
||||
file = ERR_PTR(err);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return file;
|
||||
}
|
||||
}
|
||||
release_open_intent(&nd);
|
||||
path_put(&nd.path);
|
||||
err = -EACCES;
|
||||
if (!S_ISREG(nd.path.dentry->d_inode->i_mode))
|
||||
goto out_path_put;
|
||||
|
||||
if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
|
||||
goto out_path_put;
|
||||
|
||||
err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN);
|
||||
if (err)
|
||||
goto out_path_put;
|
||||
|
||||
file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE);
|
||||
if (IS_ERR(file))
|
||||
return file;
|
||||
|
||||
err = deny_write_access(file);
|
||||
if (err) {
|
||||
fput(file);
|
||||
goto out;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
return file;
|
||||
|
||||
out_path_put:
|
||||
release_open_intent(&nd);
|
||||
path_put(&nd.path);
|
||||
out:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL(open_exec);
|
||||
|
||||
int kernel_read(struct file *file, unsigned long offset,
|
||||
|
|
|
@ -294,7 +294,7 @@ ext2_check_acl(struct inode *inode, int mask)
|
|||
}
|
||||
|
||||
int
|
||||
ext2_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
ext2_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return generic_permission(inode, mask, ext2_check_acl);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ static inline int ext2_acl_count(size_t size)
|
|||
#define EXT2_ACL_NOT_CACHED ((void *)-1)
|
||||
|
||||
/* acl.c */
|
||||
extern int ext2_permission (struct inode *, int, struct nameidata *);
|
||||
extern int ext2_permission (struct inode *, int);
|
||||
extern int ext2_acl_chmod (struct inode *);
|
||||
extern int ext2_init_acl (struct inode *, struct inode *);
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ ext3_check_acl(struct inode *inode, int mask)
|
|||
}
|
||||
|
||||
int
|
||||
ext3_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
ext3_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return generic_permission(inode, mask, ext3_check_acl);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ static inline int ext3_acl_count(size_t size)
|
|||
#define EXT3_ACL_NOT_CACHED ((void *)-1)
|
||||
|
||||
/* acl.c */
|
||||
extern int ext3_permission (struct inode *, int, struct nameidata *);
|
||||
extern int ext3_permission (struct inode *, int);
|
||||
extern int ext3_acl_chmod (struct inode *);
|
||||
extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ ext4_check_acl(struct inode *inode, int mask)
|
|||
}
|
||||
|
||||
int
|
||||
ext4_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
ext4_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return generic_permission(inode, mask, ext4_check_acl);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ static inline int ext4_acl_count(size_t size)
|
|||
#define EXT4_ACL_NOT_CACHED ((void *)-1)
|
||||
|
||||
/* acl.c */
|
||||
extern int ext4_permission (struct inode *, int, struct nameidata *);
|
||||
extern int ext4_permission (struct inode *, int);
|
||||
extern int ext4_acl_chmod (struct inode *);
|
||||
extern int ext4_init_acl (handle_t *, struct inode *, struct inode *);
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <linux/writeback.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
int fat_generic_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
|
@ -64,6 +66,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
|
|||
|
||||
/* Equivalent to a chmod() */
|
||||
ia.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
ia.ia_ctime = current_fs_time(inode->i_sb);
|
||||
if (is_dir) {
|
||||
ia.ia_mode = MSDOS_MKMODE(attr,
|
||||
S_IRWXUGO & ~sbi->options.fs_dmask)
|
||||
|
@ -90,11 +93,21 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
|
|||
}
|
||||
}
|
||||
|
||||
/* This MUST be done before doing anything irreversible... */
|
||||
err = notify_change(filp->f_path.dentry, &ia);
|
||||
/*
|
||||
* The security check is questionable... We single
|
||||
* out the RO attribute for checking by the security
|
||||
* module, just because it maps to a file mode.
|
||||
*/
|
||||
err = security_inode_setattr(filp->f_path.dentry, &ia);
|
||||
if (err)
|
||||
goto up;
|
||||
|
||||
/* This MUST be done before doing anything irreversible... */
|
||||
err = fat_setattr(filp->f_path.dentry, &ia);
|
||||
if (err)
|
||||
goto up;
|
||||
|
||||
fsnotify_change(filp->f_path.dentry, ia.ia_valid);
|
||||
if (sbi->options.sys_immutable) {
|
||||
if (attr & ATTR_SYS)
|
||||
inode->i_flags |= S_IMMUTABLE;
|
||||
|
|
33
fs/fcntl.c
33
fs/fcntl.c
|
@ -64,11 +64,6 @@ static int locate_fd(unsigned int orig_start, int cloexec)
|
|||
struct fdtable *fdt;
|
||||
|
||||
spin_lock(&files->file_lock);
|
||||
|
||||
error = -EINVAL;
|
||||
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||
goto out;
|
||||
|
||||
repeat:
|
||||
fdt = files_fdtable(files);
|
||||
/*
|
||||
|
@ -83,10 +78,6 @@ repeat:
|
|||
if (start < fdt->max_fds)
|
||||
newfd = find_next_zero_bit(fdt->open_fds->fds_bits,
|
||||
fdt->max_fds, start);
|
||||
|
||||
error = -EMFILE;
|
||||
if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||
goto out;
|
||||
|
||||
error = expand_files(files, newfd);
|
||||
if (error < 0)
|
||||
|
@ -135,20 +126,20 @@ asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags)
|
|||
if ((flags & ~O_CLOEXEC) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(oldfd == newfd))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&files->file_lock);
|
||||
if (!(file = fcheck(oldfd)))
|
||||
goto out_unlock;
|
||||
err = newfd;
|
||||
if (newfd == oldfd)
|
||||
goto out_unlock;
|
||||
err = -EBADF;
|
||||
if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||
goto out_unlock;
|
||||
get_file(file); /* We are now finished with oldfd */
|
||||
|
||||
err = expand_files(files, newfd);
|
||||
if (err < 0)
|
||||
if (unlikely(err < 0)) {
|
||||
if (err == -EMFILE)
|
||||
err = -EBADF;
|
||||
goto out_fput;
|
||||
}
|
||||
|
||||
/* To avoid races with open() and dup(), we will mark the fd as
|
||||
* in-use in the open-file bitmap throughout the entire dup2()
|
||||
|
@ -189,6 +180,14 @@ out_fput:
|
|||
|
||||
asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
|
||||
{
|
||||
if (unlikely(newfd == oldfd)) { /* corner case */
|
||||
struct files_struct *files = current->files;
|
||||
rcu_read_lock();
|
||||
if (!fcheck_files(files, oldfd))
|
||||
oldfd = -EBADF;
|
||||
rcu_read_unlock();
|
||||
return oldfd;
|
||||
}
|
||||
return sys_dup3(oldfd, newfd, 0);
|
||||
}
|
||||
|
||||
|
@ -321,6 +320,8 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
|||
switch (cmd) {
|
||||
case F_DUPFD:
|
||||
case F_DUPFD_CLOEXEC:
|
||||
if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||
break;
|
||||
get_file(filp);
|
||||
err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC);
|
||||
break;
|
||||
|
|
|
@ -57,7 +57,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
|
|||
* POSIX.1 says that O_NONBLOCK means return with the FIFO
|
||||
* opened, even when there is no process writing the FIFO.
|
||||
*/
|
||||
filp->f_op = &read_fifo_fops;
|
||||
filp->f_op = &read_pipefifo_fops;
|
||||
pipe->r_counter++;
|
||||
if (pipe->readers++ == 0)
|
||||
wake_up_partner(inode);
|
||||
|
@ -86,7 +86,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
|
|||
if ((filp->f_flags & O_NONBLOCK) && !pipe->readers)
|
||||
goto err;
|
||||
|
||||
filp->f_op = &write_fifo_fops;
|
||||
filp->f_op = &write_pipefifo_fops;
|
||||
pipe->w_counter++;
|
||||
if (!pipe->writers++)
|
||||
wake_up_partner(inode);
|
||||
|
@ -105,7 +105,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
|
|||
* This implementation will NEVER block on a O_RDWR open, since
|
||||
* the process can at least talk to itself.
|
||||
*/
|
||||
filp->f_op = &rdwr_fifo_fops;
|
||||
filp->f_op = &rdwr_pipefifo_fops;
|
||||
|
||||
pipe->readers++;
|
||||
pipe->writers++;
|
||||
|
@ -151,5 +151,5 @@ err_nocleanup:
|
|||
* depending on the access mode of the file...
|
||||
*/
|
||||
const struct file_operations def_fifo_fops = {
|
||||
.open = fifo_open, /* will set read or write pipe_fops */
|
||||
.open = fifo_open, /* will set read_ or write_pipefifo_fops */
|
||||
};
|
||||
|
|
|
@ -250,9 +250,18 @@ int expand_files(struct files_struct *files, int nr)
|
|||
struct fdtable *fdt;
|
||||
|
||||
fdt = files_fdtable(files);
|
||||
|
||||
/*
|
||||
* N.B. For clone tasks sharing a files structure, this test
|
||||
* will limit the total number of files that can be opened.
|
||||
*/
|
||||
if (nr >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||
return -EMFILE;
|
||||
|
||||
/* Do we need to expand? */
|
||||
if (nr < fdt->max_fds)
|
||||
return 0;
|
||||
|
||||
/* Can we expand? */
|
||||
if (nr >= sysctl_nr_open)
|
||||
return -EMFILE;
|
||||
|
|
|
@ -120,7 +120,7 @@ struct file *get_empty_filp(void)
|
|||
|
||||
tsk = current;
|
||||
INIT_LIST_HEAD(&f->f_u.fu_list);
|
||||
atomic_set(&f->f_count, 1);
|
||||
atomic_long_set(&f->f_count, 1);
|
||||
rwlock_init(&f->f_owner.lock);
|
||||
f->f_uid = tsk->fsuid;
|
||||
f->f_gid = tsk->fsgid;
|
||||
|
@ -219,7 +219,7 @@ EXPORT_SYMBOL(init_file);
|
|||
|
||||
void fput(struct file *file)
|
||||
{
|
||||
if (atomic_dec_and_test(&file->f_count))
|
||||
if (atomic_long_dec_and_test(&file->f_count))
|
||||
__fput(file);
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ struct file *fget(unsigned int fd)
|
|||
rcu_read_lock();
|
||||
file = fcheck_files(files, fd);
|
||||
if (file) {
|
||||
if (!atomic_inc_not_zero(&file->f_count)) {
|
||||
if (!atomic_long_inc_not_zero(&file->f_count)) {
|
||||
/* File object ref couldn't be taken */
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
|
@ -326,7 +326,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
|
|||
rcu_read_lock();
|
||||
file = fcheck_files(files, fd);
|
||||
if (file) {
|
||||
if (atomic_inc_not_zero(&file->f_count))
|
||||
if (atomic_long_inc_not_zero(&file->f_count))
|
||||
*fput_needed = 1;
|
||||
else
|
||||
/* Didn't get the reference, someone's freed */
|
||||
|
@ -341,7 +341,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
|
|||
|
||||
void put_filp(struct file *file)
|
||||
{
|
||||
if (atomic_dec_and_test(&file->f_count)) {
|
||||
if (atomic_long_dec_and_test(&file->f_count)) {
|
||||
security_file_free(file);
|
||||
file_kill(file);
|
||||
file_free(file);
|
||||
|
|
|
@ -898,7 +898,7 @@ static int fuse_access(struct inode *inode, int mask)
|
|||
return PTR_ERR(req);
|
||||
|
||||
memset(&inarg, 0, sizeof(inarg));
|
||||
inarg.mask = mask;
|
||||
inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC);
|
||||
req->in.h.opcode = FUSE_ACCESS;
|
||||
req->in.h.nodeid = get_node_id(inode);
|
||||
req->in.numargs = 1;
|
||||
|
@ -927,7 +927,7 @@ static int fuse_access(struct inode *inode, int mask)
|
|||
* access request is sent. Execute permission is still checked
|
||||
* locally based on file mode.
|
||||
*/
|
||||
static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
static int fuse_permission(struct inode *inode, int mask)
|
||||
{
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
bool refreshed = false;
|
||||
|
@ -962,7 +962,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
|
|||
exist. So if permissions are revoked this won't be
|
||||
noticed immediately, only after the attribute
|
||||
timeout has expired */
|
||||
} else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) {
|
||||
} else if (mask & MAY_ACCESS) {
|
||||
err = fuse_access(inode, mask);
|
||||
} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
||||
if (!(inode->i_mode & S_IXUGO)) {
|
||||
|
|
|
@ -893,7 +893,7 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
|||
if (count == 0)
|
||||
goto out;
|
||||
|
||||
err = remove_suid(file->f_path.dentry);
|
||||
err = file_remove_suid(file);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
|
|
@ -448,7 +448,7 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
|
|||
struct qstr qstr;
|
||||
struct inode *inode;
|
||||
gfs2_str2qstr(&qstr, name);
|
||||
inode = gfs2_lookupi(dip, &qstr, 1, NULL);
|
||||
inode = gfs2_lookupi(dip, &qstr, 1);
|
||||
/* gfs2_lookupi has inconsistent callers: vfs
|
||||
* related routines expect NULL for no entry found,
|
||||
* gfs2_lookup_simple callers expect ENOENT
|
||||
|
@ -477,7 +477,7 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
|
|||
*/
|
||||
|
||||
struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
||||
int is_root, struct nameidata *nd)
|
||||
int is_root)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct gfs2_inode *dip = GFS2_I(dir);
|
||||
|
@ -1173,7 +1173,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
|
|||
break;
|
||||
}
|
||||
|
||||
tmp = gfs2_lookupi(dir, &dotdot, 1, NULL);
|
||||
tmp = gfs2_lookupi(dir, &dotdot, 1);
|
||||
if (IS_ERR(tmp)) {
|
||||
error = PTR_ERR(tmp);
|
||||
break;
|
||||
|
|
|
@ -83,7 +83,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip);
|
|||
int gfs2_dinode_dealloc(struct gfs2_inode *inode);
|
||||
int gfs2_change_nlink(struct gfs2_inode *ip, int diff);
|
||||
struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
||||
int is_root, struct nameidata *nd);
|
||||
int is_root);
|
||||
struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
|
||||
unsigned int mode, dev_t dev);
|
||||
int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
|
||||
|
|
|
@ -134,7 +134,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child)
|
|||
struct dentry *dentry;
|
||||
|
||||
gfs2_str2qstr(&dotdot, "..");
|
||||
inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL);
|
||||
inode = gfs2_lookupi(child->d_inode, &dotdot, 1);
|
||||
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
|
|
@ -74,7 +74,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
|
|||
return PTR_ERR(inode);
|
||||
}
|
||||
|
||||
inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
|
||||
inode = gfs2_lookupi(dir, &dentry->d_name, 0);
|
||||
if (inode) {
|
||||
if (!IS_ERR(inode)) {
|
||||
gfs2_holder_uninit(ghs);
|
||||
|
@ -109,7 +109,7 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
|||
|
||||
dentry->d_op = &gfs2_dops;
|
||||
|
||||
inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
|
||||
inode = gfs2_lookupi(dir, &dentry->d_name, 0);
|
||||
if (inode && IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
|
@ -915,12 +915,6 @@ int gfs2_permission(struct inode *inode, int mask)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int gfs2_iop_permission(struct inode *inode, int mask,
|
||||
struct nameidata *nd)
|
||||
{
|
||||
return gfs2_permission(inode, mask);
|
||||
}
|
||||
|
||||
static int setattr_size(struct inode *inode, struct iattr *attr)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
|
@ -1150,7 +1144,7 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name)
|
|||
}
|
||||
|
||||
const struct inode_operations gfs2_file_iops = {
|
||||
.permission = gfs2_iop_permission,
|
||||
.permission = gfs2_permission,
|
||||
.setattr = gfs2_setattr,
|
||||
.getattr = gfs2_getattr,
|
||||
.setxattr = gfs2_setxattr,
|
||||
|
@ -1169,7 +1163,7 @@ const struct inode_operations gfs2_dir_iops = {
|
|||
.rmdir = gfs2_rmdir,
|
||||
.mknod = gfs2_mknod,
|
||||
.rename = gfs2_rename,
|
||||
.permission = gfs2_iop_permission,
|
||||
.permission = gfs2_permission,
|
||||
.setattr = gfs2_setattr,
|
||||
.getattr = gfs2_getattr,
|
||||
.setxattr = gfs2_setxattr,
|
||||
|
@ -1181,7 +1175,7 @@ const struct inode_operations gfs2_dir_iops = {
|
|||
const struct inode_operations gfs2_symlink_iops = {
|
||||
.readlink = gfs2_readlink,
|
||||
.follow_link = gfs2_follow_link,
|
||||
.permission = gfs2_iop_permission,
|
||||
.permission = gfs2_permission,
|
||||
.setattr = gfs2_setattr,
|
||||
.getattr = gfs2_getattr,
|
||||
.setxattr = gfs2_setxattr,
|
||||
|
|
|
@ -389,7 +389,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
|
|||
break;
|
||||
|
||||
INIT_LIST_HEAD(&jd->extent_list);
|
||||
jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL);
|
||||
jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1);
|
||||
if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
|
||||
if (!jd->jd_inode)
|
||||
error = -ENOENT;
|
||||
|
|
|
@ -511,8 +511,7 @@ void hfs_clear_inode(struct inode *inode)
|
|||
}
|
||||
}
|
||||
|
||||
static int hfs_permission(struct inode *inode, int mask,
|
||||
struct nameidata *nd)
|
||||
static int hfs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
if (S_ISREG(inode->i_mode) && mask & MAY_EXEC)
|
||||
return 0;
|
||||
|
@ -523,8 +522,6 @@ static int hfs_file_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
if (HFS_IS_RSRC(inode))
|
||||
inode = HFS_I(inode)->rsrc_inode;
|
||||
if (atomic_read(&file->f_count) != 1)
|
||||
return 0;
|
||||
atomic_inc(&HFS_I(inode)->opencnt);
|
||||
return 0;
|
||||
}
|
||||
|
@ -535,8 +532,6 @@ static int hfs_file_release(struct inode *inode, struct file *file)
|
|||
|
||||
if (HFS_IS_RSRC(inode))
|
||||
inode = HFS_I(inode)->rsrc_inode;
|
||||
if (atomic_read(&file->f_count) != 0)
|
||||
return 0;
|
||||
if (atomic_dec_and_test(&HFS_I(inode)->opencnt)) {
|
||||
mutex_lock(&inode->i_mutex);
|
||||
hfs_file_truncate(inode);
|
||||
|
|
|
@ -238,7 +238,7 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
|
|||
perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
|
||||
}
|
||||
|
||||
static int hfsplus_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
static int hfsplus_permission(struct inode *inode, int mask)
|
||||
{
|
||||
/* MAY_EXEC is also used for lookup, if no x bit is set allow lookup,
|
||||
* open_exec has the same test, so it's still not executable, if a x bit
|
||||
|
@ -254,8 +254,6 @@ static int hfsplus_file_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
if (HFSPLUS_IS_RSRC(inode))
|
||||
inode = HFSPLUS_I(inode).rsrc_inode;
|
||||
if (atomic_read(&file->f_count) != 1)
|
||||
return 0;
|
||||
atomic_inc(&HFSPLUS_I(inode).opencnt);
|
||||
return 0;
|
||||
}
|
||||
|
@ -266,8 +264,6 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
|
|||
|
||||
if (HFSPLUS_IS_RSRC(inode))
|
||||
inode = HFSPLUS_I(inode).rsrc_inode;
|
||||
if (atomic_read(&file->f_count) != 0)
|
||||
return 0;
|
||||
if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) {
|
||||
mutex_lock(&inode->i_mutex);
|
||||
hfsplus_file_truncate(inode);
|
||||
|
|
|
@ -822,7 +822,7 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
|
|||
return err;
|
||||
}
|
||||
|
||||
int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
|
||||
int hostfs_permission(struct inode *ino, int desired)
|
||||
{
|
||||
char *name;
|
||||
int r = 0, w = 0, x = 0, err;
|
||||
|
|
|
@ -415,7 +415,7 @@ again:
|
|||
d_drop(dentry);
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (atomic_read(&dentry->d_count) > 1 ||
|
||||
permission(inode, MAY_WRITE, NULL) ||
|
||||
generic_permission(inode, MAY_WRITE, NULL) ||
|
||||
!S_ISREG(inode->i_mode) ||
|
||||
get_write_access(inode)) {
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
|
|
@ -655,20 +655,13 @@ static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
|||
return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd);
|
||||
}
|
||||
|
||||
int hppfs_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
{
|
||||
return generic_permission(inode, mask, NULL);
|
||||
}
|
||||
|
||||
static const struct inode_operations hppfs_dir_iops = {
|
||||
.lookup = hppfs_lookup,
|
||||
.permission = hppfs_permission,
|
||||
};
|
||||
|
||||
static const struct inode_operations hppfs_link_iops = {
|
||||
.readlink = hppfs_readlink,
|
||||
.follow_link = hppfs_follow_link,
|
||||
.permission = hppfs_permission,
|
||||
};
|
||||
|
||||
static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
|
||||
|
|
|
@ -354,20 +354,20 @@ static void inotify_dev_event_dequeue(struct inotify_device *dev)
|
|||
}
|
||||
|
||||
/*
|
||||
* find_inode - resolve a user-given path to a specific inode and return a nd
|
||||
* find_inode - resolve a user-given path to a specific inode
|
||||
*/
|
||||
static int find_inode(const char __user *dirname, struct nameidata *nd,
|
||||
static int find_inode(const char __user *dirname, struct path *path,
|
||||
unsigned flags)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = __user_walk(dirname, flags, nd);
|
||||
error = user_path_at(AT_FDCWD, dirname, flags, path);
|
||||
if (error)
|
||||
return error;
|
||||
/* you can only watch an inode if you have read permissions on it */
|
||||
error = vfs_permission(nd, MAY_READ);
|
||||
error = inode_permission(path->dentry->d_inode, MAY_READ);
|
||||
if (error)
|
||||
path_put(&nd->path);
|
||||
path_put(path);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -650,11 +650,11 @@ asmlinkage long sys_inotify_init(void)
|
|||
return sys_inotify_init1(0);
|
||||
}
|
||||
|
||||
asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
|
||||
asmlinkage long sys_inotify_add_watch(int fd, const char __user *pathname, u32 mask)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct inotify_device *dev;
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
struct file *filp;
|
||||
int ret, fput_needed;
|
||||
unsigned flags = 0;
|
||||
|
@ -674,12 +674,12 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
|
|||
if (mask & IN_ONLYDIR)
|
||||
flags |= LOOKUP_DIRECTORY;
|
||||
|
||||
ret = find_inode(path, &nd, flags);
|
||||
ret = find_inode(pathname, &path, flags);
|
||||
if (unlikely(ret))
|
||||
goto fput_and_out;
|
||||
|
||||
/* inode held in place by reference to nd; dev by fget on fd */
|
||||
inode = nd.path.dentry->d_inode;
|
||||
/* inode held in place by reference to path; dev by fget on fd */
|
||||
inode = path.dentry->d_inode;
|
||||
dev = filp->private_data;
|
||||
|
||||
mutex_lock(&dev->up_mutex);
|
||||
|
@ -688,7 +688,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
|
|||
ret = create_watch(dev, inode, mask);
|
||||
mutex_unlock(&dev->up_mutex);
|
||||
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
fput_and_out:
|
||||
fput_light(filp, fput_needed);
|
||||
return ret;
|
||||
|
|
|
@ -314,7 +314,7 @@ static int jffs2_check_acl(struct inode *inode, int mask)
|
|||
return -EAGAIN;
|
||||
}
|
||||
|
||||
int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
int jffs2_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return generic_permission(inode, mask, jffs2_check_acl);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ struct jffs2_acl_header {
|
|||
|
||||
#define JFFS2_ACL_NOT_CACHED ((void *)-1)
|
||||
|
||||
extern int jffs2_permission(struct inode *, int, struct nameidata *);
|
||||
extern int jffs2_permission(struct inode *, int);
|
||||
extern int jffs2_acl_chmod(struct inode *);
|
||||
extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *);
|
||||
extern int jffs2_init_acl_post(struct inode *);
|
||||
|
|
|
@ -140,7 +140,7 @@ static int jfs_check_acl(struct inode *inode, int mask)
|
|||
return -EAGAIN;
|
||||
}
|
||||
|
||||
int jfs_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
int jfs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
return generic_permission(inode, mask, jfs_check_acl);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#ifdef CONFIG_JFS_POSIX_ACL
|
||||
|
||||
int jfs_permission(struct inode *, int, struct nameidata *);
|
||||
int jfs_permission(struct inode *, int);
|
||||
int jfs_init_acl(tid_t, struct inode *, struct inode *);
|
||||
int jfs_setattr(struct dentry *, struct iattr *);
|
||||
|
||||
|
|
354
fs/namei.c
354
fs/namei.c
|
@ -31,7 +31,6 @@
|
|||
#include <linux/file.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/device_cgroup.h>
|
||||
#include <asm/namei.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
|
||||
|
@ -185,6 +184,8 @@ int generic_permission(struct inode *inode, int mask,
|
|||
{
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
|
||||
|
||||
if (current->fsuid == inode->i_uid)
|
||||
mode >>= 6;
|
||||
else {
|
||||
|
@ -203,7 +204,7 @@ int generic_permission(struct inode *inode, int mask,
|
|||
/*
|
||||
* If the DACs are ok we don't need any capability check.
|
||||
*/
|
||||
if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask))
|
||||
if ((mask & ~mode) == 0)
|
||||
return 0;
|
||||
|
||||
check_capabilities:
|
||||
|
@ -226,13 +227,9 @@ int generic_permission(struct inode *inode, int mask,
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
int permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
int inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int retval, submask;
|
||||
struct vfsmount *mnt = NULL;
|
||||
|
||||
if (nd)
|
||||
mnt = nd->path.mnt;
|
||||
int retval;
|
||||
|
||||
if (mask & MAY_WRITE) {
|
||||
umode_t mode = inode->i_mode;
|
||||
|
@ -251,19 +248,9 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
||||
/*
|
||||
* MAY_EXEC on regular files is denied if the fs is mounted
|
||||
* with the "noexec" flag.
|
||||
*/
|
||||
if (mnt && (mnt->mnt_flags & MNT_NOEXEC))
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* Ordinary permission routines do not understand MAY_APPEND. */
|
||||
submask = mask & ~MAY_APPEND;
|
||||
if (inode->i_op && inode->i_op->permission) {
|
||||
retval = inode->i_op->permission(inode, submask, nd);
|
||||
retval = inode->i_op->permission(inode, mask);
|
||||
if (!retval) {
|
||||
/*
|
||||
* Exec permission on a regular file is denied if none
|
||||
|
@ -277,7 +264,7 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
|
|||
return -EACCES;
|
||||
}
|
||||
} else {
|
||||
retval = generic_permission(inode, submask, NULL);
|
||||
retval = generic_permission(inode, mask, NULL);
|
||||
}
|
||||
if (retval)
|
||||
return retval;
|
||||
|
@ -286,7 +273,8 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
return security_inode_permission(inode, mask, nd);
|
||||
return security_inode_permission(inode,
|
||||
mask & (MAY_READ|MAY_WRITE|MAY_EXEC));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -301,7 +289,7 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
|
|||
*/
|
||||
int vfs_permission(struct nameidata *nd, int mask)
|
||||
{
|
||||
return permission(nd->path.dentry->d_inode, mask, nd);
|
||||
return inode_permission(nd->path.dentry->d_inode, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -318,7 +306,7 @@ int vfs_permission(struct nameidata *nd, int mask)
|
|||
*/
|
||||
int file_permission(struct file *file, int mask)
|
||||
{
|
||||
return permission(file->f_path.dentry->d_inode, mask, NULL);
|
||||
return inode_permission(file->f_path.dentry->d_inode, mask);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -459,8 +447,7 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name,
|
|||
* short-cut DAC fails, then call permission() to do more
|
||||
* complete permission check.
|
||||
*/
|
||||
static int exec_permission_lite(struct inode *inode,
|
||||
struct nameidata *nd)
|
||||
static int exec_permission_lite(struct inode *inode)
|
||||
{
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
|
@ -486,7 +473,7 @@ static int exec_permission_lite(struct inode *inode,
|
|||
|
||||
return -EACCES;
|
||||
ok:
|
||||
return security_inode_permission(inode, MAY_EXEC, nd);
|
||||
return security_inode_permission(inode, MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -519,7 +506,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
|
|||
*/
|
||||
result = d_lookup(parent, name);
|
||||
if (!result) {
|
||||
struct dentry * dentry = d_alloc(parent, name);
|
||||
struct dentry *dentry;
|
||||
|
||||
/* Don't create child dentry for a dead directory. */
|
||||
result = ERR_PTR(-ENOENT);
|
||||
if (IS_DEADDIR(dir))
|
||||
goto out_unlock;
|
||||
|
||||
dentry = d_alloc(parent, name);
|
||||
result = ERR_PTR(-ENOMEM);
|
||||
if (dentry) {
|
||||
result = dir->i_op->lookup(dir, dentry, nd);
|
||||
|
@ -528,6 +522,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
|
|||
else
|
||||
result = dentry;
|
||||
}
|
||||
out_unlock:
|
||||
mutex_unlock(&dir->i_mutex);
|
||||
return result;
|
||||
}
|
||||
|
@ -545,27 +540,16 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
|
|||
return result;
|
||||
}
|
||||
|
||||
static int __emul_lookup_dentry(const char *, struct nameidata *);
|
||||
|
||||
/* SMP-safe */
|
||||
static __always_inline int
|
||||
static __always_inline void
|
||||
walk_init_root(const char *name, struct nameidata *nd)
|
||||
{
|
||||
struct fs_struct *fs = current->fs;
|
||||
|
||||
read_lock(&fs->lock);
|
||||
if (fs->altroot.dentry && !(nd->flags & LOOKUP_NOALT)) {
|
||||
nd->path = fs->altroot;
|
||||
path_get(&fs->altroot);
|
||||
read_unlock(&fs->lock);
|
||||
if (__emul_lookup_dentry(name,nd))
|
||||
return 0;
|
||||
read_lock(&fs->lock);
|
||||
}
|
||||
nd->path = fs->root;
|
||||
path_get(&fs->root);
|
||||
read_unlock(&fs->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -606,12 +590,9 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
|
|||
|
||||
if (*link == '/') {
|
||||
path_put(&nd->path);
|
||||
if (!walk_init_root(link, nd))
|
||||
/* weird __emul_prefix() stuff did it */
|
||||
goto out;
|
||||
walk_init_root(link, nd);
|
||||
}
|
||||
res = link_path_walk(link, nd);
|
||||
out:
|
||||
if (nd->depth || res || nd->last_type!=LAST_NORM)
|
||||
return res;
|
||||
/*
|
||||
|
@ -889,7 +870,7 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
|
|||
unsigned int c;
|
||||
|
||||
nd->flags |= LOOKUP_CONTINUE;
|
||||
err = exec_permission_lite(inode, nd);
|
||||
err = exec_permission_lite(inode);
|
||||
if (err == -EAGAIN)
|
||||
err = vfs_permission(nd, MAY_EXEC);
|
||||
if (err)
|
||||
|
@ -1060,67 +1041,6 @@ static int path_walk(const char *name, struct nameidata *nd)
|
|||
return link_path_walk(name, nd);
|
||||
}
|
||||
|
||||
/*
|
||||
* SMP-safe: Returns 1 and nd will have valid dentry and mnt, if
|
||||
* everything is done. Returns 0 and drops input nd, if lookup failed;
|
||||
*/
|
||||
static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
|
||||
{
|
||||
if (path_walk(name, nd))
|
||||
return 0; /* something went wrong... */
|
||||
|
||||
if (!nd->path.dentry->d_inode ||
|
||||
S_ISDIR(nd->path.dentry->d_inode->i_mode)) {
|
||||
struct path old_path = nd->path;
|
||||
struct qstr last = nd->last;
|
||||
int last_type = nd->last_type;
|
||||
struct fs_struct *fs = current->fs;
|
||||
|
||||
/*
|
||||
* NAME was not found in alternate root or it's a directory.
|
||||
* Try to find it in the normal root:
|
||||
*/
|
||||
nd->last_type = LAST_ROOT;
|
||||
read_lock(&fs->lock);
|
||||
nd->path = fs->root;
|
||||
path_get(&fs->root);
|
||||
read_unlock(&fs->lock);
|
||||
if (path_walk(name, nd) == 0) {
|
||||
if (nd->path.dentry->d_inode) {
|
||||
path_put(&old_path);
|
||||
return 1;
|
||||
}
|
||||
path_put(&nd->path);
|
||||
}
|
||||
nd->path = old_path;
|
||||
nd->last = last;
|
||||
nd->last_type = last_type;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_fs_altroot(void)
|
||||
{
|
||||
char *emul = __emul_prefix();
|
||||
struct nameidata nd;
|
||||
struct path path = {}, old_path;
|
||||
int err;
|
||||
struct fs_struct *fs = current->fs;
|
||||
|
||||
if (!emul)
|
||||
goto set_it;
|
||||
err = path_lookup(emul, LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_NOALT, &nd);
|
||||
if (!err)
|
||||
path = nd.path;
|
||||
set_it:
|
||||
write_lock(&fs->lock);
|
||||
old_path = fs->altroot;
|
||||
fs->altroot = path;
|
||||
write_unlock(&fs->lock);
|
||||
if (old_path.dentry)
|
||||
path_put(&old_path);
|
||||
}
|
||||
|
||||
/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
|
||||
static int do_path_lookup(int dfd, const char *name,
|
||||
unsigned int flags, struct nameidata *nd)
|
||||
|
@ -1136,14 +1056,6 @@ static int do_path_lookup(int dfd, const char *name,
|
|||
|
||||
if (*name=='/') {
|
||||
read_lock(&fs->lock);
|
||||
if (fs->altroot.dentry && !(nd->flags & LOOKUP_NOALT)) {
|
||||
nd->path = fs->altroot;
|
||||
path_get(&fs->altroot);
|
||||
read_unlock(&fs->lock);
|
||||
if (__emul_lookup_dentry(name,nd))
|
||||
goto out; /* found in altroot */
|
||||
read_lock(&fs->lock);
|
||||
}
|
||||
nd->path = fs->root;
|
||||
path_get(&fs->root);
|
||||
read_unlock(&fs->lock);
|
||||
|
@ -1177,7 +1089,6 @@ static int do_path_lookup(int dfd, const char *name,
|
|||
}
|
||||
|
||||
retval = path_walk(name, nd);
|
||||
out:
|
||||
if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
|
||||
nd->path.dentry->d_inode))
|
||||
audit_inode(name, nd->path.dentry);
|
||||
|
@ -1282,19 +1193,6 @@ static int path_lookup_create(int dfd, const char *name,
|
|||
nd, open_flags, create_mode);
|
||||
}
|
||||
|
||||
int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
|
||||
struct nameidata *nd, int open_flags)
|
||||
{
|
||||
char *tmp = getname(name);
|
||||
int err = PTR_ERR(tmp);
|
||||
|
||||
if (!IS_ERR(tmp)) {
|
||||
err = __path_lookup_intent_open(AT_FDCWD, tmp, lookup_flags, nd, open_flags, 0);
|
||||
putname(tmp);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct dentry *__lookup_hash(struct qstr *name,
|
||||
struct dentry *base, struct nameidata *nd)
|
||||
{
|
||||
|
@ -1317,7 +1215,14 @@ static struct dentry *__lookup_hash(struct qstr *name,
|
|||
|
||||
dentry = cached_lookup(base, name, nd);
|
||||
if (!dentry) {
|
||||
struct dentry *new = d_alloc(base, name);
|
||||
struct dentry *new;
|
||||
|
||||
/* Don't create child dentry for a dead directory. */
|
||||
dentry = ERR_PTR(-ENOENT);
|
||||
if (IS_DEADDIR(inode))
|
||||
goto out;
|
||||
|
||||
new = d_alloc(base, name);
|
||||
dentry = ERR_PTR(-ENOMEM);
|
||||
if (!new)
|
||||
goto out;
|
||||
|
@ -1340,7 +1245,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
|
|||
{
|
||||
int err;
|
||||
|
||||
err = permission(nd->path.dentry->d_inode, MAY_EXEC, nd);
|
||||
err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return __lookup_hash(&nd->last, nd->path.dentry, nd);
|
||||
|
@ -1388,7 +1293,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
|||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = permission(base->d_inode, MAY_EXEC, NULL);
|
||||
err = inode_permission(base->d_inode, MAY_EXEC);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return __lookup_hash(&this, base, NULL);
|
||||
|
@ -1416,22 +1321,40 @@ struct dentry *lookup_one_noperm(const char *name, struct dentry *base)
|
|||
return __lookup_hash(&this, base, NULL);
|
||||
}
|
||||
|
||||
int __user_walk_fd(int dfd, const char __user *name, unsigned flags,
|
||||
struct nameidata *nd)
|
||||
int user_path_at(int dfd, const char __user *name, unsigned flags,
|
||||
struct path *path)
|
||||
{
|
||||
struct nameidata nd;
|
||||
char *tmp = getname(name);
|
||||
int err = PTR_ERR(tmp);
|
||||
|
||||
if (!IS_ERR(tmp)) {
|
||||
err = do_path_lookup(dfd, tmp, flags, nd);
|
||||
|
||||
BUG_ON(flags & LOOKUP_PARENT);
|
||||
|
||||
err = do_path_lookup(dfd, tmp, flags, &nd);
|
||||
putname(tmp);
|
||||
if (!err)
|
||||
*path = nd.path;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
|
||||
static int user_path_parent(int dfd, const char __user *path,
|
||||
struct nameidata *nd, char **name)
|
||||
{
|
||||
return __user_walk_fd(AT_FDCWD, name, flags, nd);
|
||||
char *s = getname(path);
|
||||
int error;
|
||||
|
||||
if (IS_ERR(s))
|
||||
return PTR_ERR(s);
|
||||
|
||||
error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd);
|
||||
if (error)
|
||||
putname(s);
|
||||
else
|
||||
*name = s;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1478,7 +1401,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
|
|||
BUG_ON(victim->d_parent->d_inode != dir);
|
||||
audit_inode_child(victim->d_name.name, victim, dir);
|
||||
|
||||
error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
|
||||
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
if (error)
|
||||
return error;
|
||||
if (IS_APPEND(dir))
|
||||
|
@ -1515,7 +1438,7 @@ static inline int may_create(struct inode *dir, struct dentry *child,
|
|||
return -EEXIST;
|
||||
if (IS_DEADDIR(dir))
|
||||
return -ENOENT;
|
||||
return permission(dir,MAY_WRITE | MAY_EXEC, nd);
|
||||
return inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1755,7 +1678,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
|
|||
int will_write;
|
||||
int flag = open_to_namei_flags(open_flag);
|
||||
|
||||
acc_mode = ACC_MODE(flag);
|
||||
acc_mode = MAY_OPEN | ACC_MODE(flag);
|
||||
|
||||
/* O_TRUNC implies we need access checks for write permissions */
|
||||
if (flag & O_TRUNC)
|
||||
|
@ -2071,20 +1994,18 @@ static int may_mknod(mode_t mode)
|
|||
asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
|
||||
unsigned dev)
|
||||
{
|
||||
int error = 0;
|
||||
char * tmp;
|
||||
struct dentry * dentry;
|
||||
int error;
|
||||
char *tmp;
|
||||
struct dentry *dentry;
|
||||
struct nameidata nd;
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
return -EPERM;
|
||||
tmp = getname(filename);
|
||||
if (IS_ERR(tmp))
|
||||
return PTR_ERR(tmp);
|
||||
|
||||
error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
|
||||
error = user_path_parent(dfd, filename, &nd, &tmp);
|
||||
if (error)
|
||||
goto out;
|
||||
return error;
|
||||
|
||||
dentry = lookup_create(&nd, 0);
|
||||
if (IS_ERR(dentry)) {
|
||||
error = PTR_ERR(dentry);
|
||||
|
@ -2116,7 +2037,6 @@ out_dput:
|
|||
out_unlock:
|
||||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
path_put(&nd.path);
|
||||
out:
|
||||
putname(tmp);
|
||||
|
||||
return error;
|
||||
|
@ -2156,14 +2076,10 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
|
|||
struct dentry *dentry;
|
||||
struct nameidata nd;
|
||||
|
||||
tmp = getname(pathname);
|
||||
error = PTR_ERR(tmp);
|
||||
if (IS_ERR(tmp))
|
||||
error = user_path_parent(dfd, pathname, &nd, &tmp);
|
||||
if (error)
|
||||
goto out_err;
|
||||
|
||||
error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
|
||||
if (error)
|
||||
goto out;
|
||||
dentry = lookup_create(&nd, 1);
|
||||
error = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry))
|
||||
|
@ -2181,7 +2097,6 @@ out_dput:
|
|||
out_unlock:
|
||||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
path_put(&nd.path);
|
||||
out:
|
||||
putname(tmp);
|
||||
out_err:
|
||||
return error;
|
||||
|
@ -2259,13 +2174,9 @@ static long do_rmdir(int dfd, const char __user *pathname)
|
|||
struct dentry *dentry;
|
||||
struct nameidata nd;
|
||||
|
||||
name = getname(pathname);
|
||||
if(IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
|
||||
error = user_path_parent(dfd, pathname, &nd, &name);
|
||||
if (error)
|
||||
goto exit;
|
||||
return error;
|
||||
|
||||
switch(nd.last_type) {
|
||||
case LAST_DOTDOT:
|
||||
|
@ -2294,7 +2205,6 @@ exit2:
|
|||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
exit1:
|
||||
path_put(&nd.path);
|
||||
exit:
|
||||
putname(name);
|
||||
return error;
|
||||
}
|
||||
|
@ -2343,19 +2253,16 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
*/
|
||||
static long do_unlinkat(int dfd, const char __user *pathname)
|
||||
{
|
||||
int error = 0;
|
||||
char * name;
|
||||
int error;
|
||||
char *name;
|
||||
struct dentry *dentry;
|
||||
struct nameidata nd;
|
||||
struct inode *inode = NULL;
|
||||
|
||||
name = getname(pathname);
|
||||
if(IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
|
||||
error = user_path_parent(dfd, pathname, &nd, &name);
|
||||
if (error)
|
||||
goto exit;
|
||||
return error;
|
||||
|
||||
error = -EISDIR;
|
||||
if (nd.last_type != LAST_NORM)
|
||||
goto exit1;
|
||||
|
@ -2382,7 +2289,6 @@ static long do_unlinkat(int dfd, const char __user *pathname)
|
|||
iput(inode); /* truncate the inode here */
|
||||
exit1:
|
||||
path_put(&nd.path);
|
||||
exit:
|
||||
putname(name);
|
||||
return error;
|
||||
|
||||
|
@ -2408,7 +2314,7 @@ asmlinkage long sys_unlink(const char __user *pathname)
|
|||
return do_unlinkat(AT_FDCWD, pathname);
|
||||
}
|
||||
|
||||
int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode)
|
||||
int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
|
||||
{
|
||||
int error = may_create(dir, dentry, NULL);
|
||||
|
||||
|
@ -2432,23 +2338,20 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i
|
|||
asmlinkage long sys_symlinkat(const char __user *oldname,
|
||||
int newdfd, const char __user *newname)
|
||||
{
|
||||
int error = 0;
|
||||
char * from;
|
||||
char * to;
|
||||
int error;
|
||||
char *from;
|
||||
char *to;
|
||||
struct dentry *dentry;
|
||||
struct nameidata nd;
|
||||
|
||||
from = getname(oldname);
|
||||
if(IS_ERR(from))
|
||||
if (IS_ERR(from))
|
||||
return PTR_ERR(from);
|
||||
to = getname(newname);
|
||||
error = PTR_ERR(to);
|
||||
if (IS_ERR(to))
|
||||
|
||||
error = user_path_parent(newdfd, newname, &nd, &to);
|
||||
if (error)
|
||||
goto out_putname;
|
||||
|
||||
error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
|
||||
if (error)
|
||||
goto out;
|
||||
dentry = lookup_create(&nd, 0);
|
||||
error = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry))
|
||||
|
@ -2457,14 +2360,13 @@ asmlinkage long sys_symlinkat(const char __user *oldname,
|
|||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
error = vfs_symlink(nd.path.dentry->d_inode, dentry, from, S_IALLUGO);
|
||||
error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
out_unlock:
|
||||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
path_put(&nd.path);
|
||||
out:
|
||||
putname(to);
|
||||
out_putname:
|
||||
putname(from);
|
||||
|
@ -2498,19 +2400,19 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
|
|||
return -EPERM;
|
||||
if (!dir->i_op || !dir->i_op->link)
|
||||
return -EPERM;
|
||||
if (S_ISDIR(old_dentry->d_inode->i_mode))
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
return -EPERM;
|
||||
|
||||
error = security_inode_link(old_dentry, dir, new_dentry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mutex_lock(&old_dentry->d_inode->i_mutex);
|
||||
mutex_lock(&inode->i_mutex);
|
||||
DQUOT_INIT(dir);
|
||||
error = dir->i_op->link(old_dentry, dir, new_dentry);
|
||||
mutex_unlock(&old_dentry->d_inode->i_mutex);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
if (!error)
|
||||
fsnotify_link(dir, old_dentry->d_inode, new_dentry);
|
||||
fsnotify_link(dir, inode, new_dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -2528,27 +2430,25 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
|
|||
int flags)
|
||||
{
|
||||
struct dentry *new_dentry;
|
||||
struct nameidata nd, old_nd;
|
||||
struct nameidata nd;
|
||||
struct path old_path;
|
||||
int error;
|
||||
char * to;
|
||||
char *to;
|
||||
|
||||
if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
to = getname(newname);
|
||||
if (IS_ERR(to))
|
||||
return PTR_ERR(to);
|
||||
|
||||
error = __user_walk_fd(olddfd, oldname,
|
||||
flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
|
||||
&old_nd);
|
||||
error = user_path_at(olddfd, oldname,
|
||||
flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
|
||||
&old_path);
|
||||
if (error)
|
||||
goto exit;
|
||||
error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
|
||||
return error;
|
||||
|
||||
error = user_path_parent(newdfd, newname, &nd, &to);
|
||||
if (error)
|
||||
goto out;
|
||||
error = -EXDEV;
|
||||
if (old_nd.path.mnt != nd.path.mnt)
|
||||
if (old_path.mnt != nd.path.mnt)
|
||||
goto out_release;
|
||||
new_dentry = lookup_create(&nd, 0);
|
||||
error = PTR_ERR(new_dentry);
|
||||
|
@ -2557,7 +2457,7 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
|
|||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
error = vfs_link(old_nd.path.dentry, nd.path.dentry->d_inode, new_dentry);
|
||||
error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(new_dentry);
|
||||
|
@ -2565,10 +2465,9 @@ out_unlock:
|
|||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
out_release:
|
||||
path_put(&nd.path);
|
||||
out:
|
||||
path_put(&old_nd.path);
|
||||
exit:
|
||||
putname(to);
|
||||
out:
|
||||
path_put(&old_path);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -2621,7 +2520,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
|
|||
* we'll need to flip '..'.
|
||||
*/
|
||||
if (new_dir != old_dir) {
|
||||
error = permission(old_dentry->d_inode, MAY_WRITE, NULL);
|
||||
error = inode_permission(old_dentry->d_inode, MAY_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@ -2724,20 +2623,22 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
return error;
|
||||
}
|
||||
|
||||
static int do_rename(int olddfd, const char *oldname,
|
||||
int newdfd, const char *newname)
|
||||
asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
|
||||
int newdfd, const char __user *newname)
|
||||
{
|
||||
int error = 0;
|
||||
struct dentry * old_dir, * new_dir;
|
||||
struct dentry * old_dentry, *new_dentry;
|
||||
struct dentry * trap;
|
||||
struct dentry *old_dir, *new_dir;
|
||||
struct dentry *old_dentry, *new_dentry;
|
||||
struct dentry *trap;
|
||||
struct nameidata oldnd, newnd;
|
||||
char *from;
|
||||
char *to;
|
||||
int error;
|
||||
|
||||
error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd);
|
||||
error = user_path_parent(olddfd, oldname, &oldnd, &from);
|
||||
if (error)
|
||||
goto exit;
|
||||
|
||||
error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd);
|
||||
error = user_path_parent(newdfd, newname, &newnd, &to);
|
||||
if (error)
|
||||
goto exit1;
|
||||
|
||||
|
@ -2799,29 +2700,11 @@ exit3:
|
|||
unlock_rename(new_dir, old_dir);
|
||||
exit2:
|
||||
path_put(&newnd.path);
|
||||
putname(to);
|
||||
exit1:
|
||||
path_put(&oldnd.path);
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
|
||||
int newdfd, const char __user *newname)
|
||||
{
|
||||
int error;
|
||||
char * from;
|
||||
char * to;
|
||||
|
||||
from = getname(oldname);
|
||||
if(IS_ERR(from))
|
||||
return PTR_ERR(from);
|
||||
to = getname(newname);
|
||||
error = PTR_ERR(to);
|
||||
if (!IS_ERR(to)) {
|
||||
error = do_rename(olddfd, from, newdfd, to);
|
||||
putname(to);
|
||||
}
|
||||
putname(from);
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -2959,8 +2842,7 @@ const struct inode_operations page_symlink_inode_operations = {
|
|||
.put_link = page_put_link,
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL(__user_walk);
|
||||
EXPORT_SYMBOL(__user_walk_fd);
|
||||
EXPORT_SYMBOL(user_path_at);
|
||||
EXPORT_SYMBOL(follow_down);
|
||||
EXPORT_SYMBOL(follow_up);
|
||||
EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
|
||||
|
@ -2975,7 +2857,7 @@ EXPORT_SYMBOL(page_symlink);
|
|||
EXPORT_SYMBOL(page_symlink_inode_operations);
|
||||
EXPORT_SYMBOL(path_lookup);
|
||||
EXPORT_SYMBOL(vfs_path_lookup);
|
||||
EXPORT_SYMBOL(permission);
|
||||
EXPORT_SYMBOL(inode_permission);
|
||||
EXPORT_SYMBOL(vfs_permission);
|
||||
EXPORT_SYMBOL(file_permission);
|
||||
EXPORT_SYMBOL(unlock_rename);
|
||||
|
|
106
fs/namespace.c
106
fs/namespace.c
|
@ -112,9 +112,13 @@ struct vfsmount *alloc_vfsmnt(const char *name)
|
|||
int err;
|
||||
|
||||
err = mnt_alloc_id(mnt);
|
||||
if (err) {
|
||||
kmem_cache_free(mnt_cache, mnt);
|
||||
return NULL;
|
||||
if (err)
|
||||
goto out_free_cache;
|
||||
|
||||
if (name) {
|
||||
mnt->mnt_devname = kstrdup(name, GFP_KERNEL);
|
||||
if (!mnt->mnt_devname)
|
||||
goto out_free_id;
|
||||
}
|
||||
|
||||
atomic_set(&mnt->mnt_count, 1);
|
||||
|
@ -127,16 +131,14 @@ struct vfsmount *alloc_vfsmnt(const char *name)
|
|||
INIT_LIST_HEAD(&mnt->mnt_slave_list);
|
||||
INIT_LIST_HEAD(&mnt->mnt_slave);
|
||||
atomic_set(&mnt->__mnt_writers, 0);
|
||||
if (name) {
|
||||
int size = strlen(name) + 1;
|
||||
char *newname = kmalloc(size, GFP_KERNEL);
|
||||
if (newname) {
|
||||
memcpy(newname, name, size);
|
||||
mnt->mnt_devname = newname;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mnt;
|
||||
|
||||
out_free_id:
|
||||
mnt_free_id(mnt);
|
||||
out_free_cache:
|
||||
kmem_cache_free(mnt_cache, mnt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1128,27 +1130,27 @@ static int do_umount(struct vfsmount *mnt, int flags)
|
|||
|
||||
asmlinkage long sys_umount(char __user * name, int flags)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int retval;
|
||||
|
||||
retval = __user_walk(name, LOOKUP_FOLLOW, &nd);
|
||||
retval = user_path(name, &path);
|
||||
if (retval)
|
||||
goto out;
|
||||
retval = -EINVAL;
|
||||
if (nd.path.dentry != nd.path.mnt->mnt_root)
|
||||
if (path.dentry != path.mnt->mnt_root)
|
||||
goto dput_and_out;
|
||||
if (!check_mnt(nd.path.mnt))
|
||||
if (!check_mnt(path.mnt))
|
||||
goto dput_and_out;
|
||||
|
||||
retval = -EPERM;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
goto dput_and_out;
|
||||
|
||||
retval = do_umount(nd.path.mnt, flags);
|
||||
retval = do_umount(path.mnt, flags);
|
||||
dput_and_out:
|
||||
/* we mustn't call path_put() as that would clear mnt_expiry_mark */
|
||||
dput(nd.path.dentry);
|
||||
mntput_no_expire(nd.path.mnt);
|
||||
dput(path.dentry);
|
||||
mntput_no_expire(path.mnt);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
@ -1972,7 +1974,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
|
|||
struct fs_struct *fs)
|
||||
{
|
||||
struct mnt_namespace *new_ns;
|
||||
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
|
||||
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL;
|
||||
struct vfsmount *p, *q;
|
||||
|
||||
new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
|
||||
|
@ -2015,10 +2017,6 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
|
|||
pwdmnt = p;
|
||||
fs->pwd.mnt = mntget(q);
|
||||
}
|
||||
if (p == fs->altroot.mnt) {
|
||||
altrootmnt = p;
|
||||
fs->altroot.mnt = mntget(q);
|
||||
}
|
||||
}
|
||||
p = next_mnt(p, mnt_ns->root);
|
||||
q = next_mnt(q, new_ns->root);
|
||||
|
@ -2029,8 +2027,6 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
|
|||
mntput(rootmnt);
|
||||
if (pwdmnt)
|
||||
mntput(pwdmnt);
|
||||
if (altrootmnt)
|
||||
mntput(altrootmnt);
|
||||
|
||||
return new_ns;
|
||||
}
|
||||
|
@ -2183,28 +2179,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
|
|||
const char __user * put_old)
|
||||
{
|
||||
struct vfsmount *tmp;
|
||||
struct nameidata new_nd, old_nd;
|
||||
struct path parent_path, root_parent, root;
|
||||
struct path new, old, parent_path, root_parent, root;
|
||||
int error;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
|
||||
&new_nd);
|
||||
error = user_path_dir(new_root, &new);
|
||||
if (error)
|
||||
goto out0;
|
||||
error = -EINVAL;
|
||||
if (!check_mnt(new_nd.path.mnt))
|
||||
if (!check_mnt(new.mnt))
|
||||
goto out1;
|
||||
|
||||
error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd);
|
||||
error = user_path_dir(put_old, &old);
|
||||
if (error)
|
||||
goto out1;
|
||||
|
||||
error = security_sb_pivotroot(&old_nd.path, &new_nd.path);
|
||||
error = security_sb_pivotroot(&old, &new);
|
||||
if (error) {
|
||||
path_put(&old_nd.path);
|
||||
path_put(&old);
|
||||
goto out1;
|
||||
}
|
||||
|
||||
|
@ -2213,69 +2207,69 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
|
|||
path_get(¤t->fs->root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
down_write(&namespace_sem);
|
||||
mutex_lock(&old_nd.path.dentry->d_inode->i_mutex);
|
||||
mutex_lock(&old.dentry->d_inode->i_mutex);
|
||||
error = -EINVAL;
|
||||
if (IS_MNT_SHARED(old_nd.path.mnt) ||
|
||||
IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) ||
|
||||
if (IS_MNT_SHARED(old.mnt) ||
|
||||
IS_MNT_SHARED(new.mnt->mnt_parent) ||
|
||||
IS_MNT_SHARED(root.mnt->mnt_parent))
|
||||
goto out2;
|
||||
if (!check_mnt(root.mnt))
|
||||
goto out2;
|
||||
error = -ENOENT;
|
||||
if (IS_DEADDIR(new_nd.path.dentry->d_inode))
|
||||
if (IS_DEADDIR(new.dentry->d_inode))
|
||||
goto out2;
|
||||
if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry))
|
||||
if (d_unhashed(new.dentry) && !IS_ROOT(new.dentry))
|
||||
goto out2;
|
||||
if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry))
|
||||
if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry))
|
||||
goto out2;
|
||||
error = -EBUSY;
|
||||
if (new_nd.path.mnt == root.mnt ||
|
||||
old_nd.path.mnt == root.mnt)
|
||||
if (new.mnt == root.mnt ||
|
||||
old.mnt == root.mnt)
|
||||
goto out2; /* loop, on the same file system */
|
||||
error = -EINVAL;
|
||||
if (root.mnt->mnt_root != root.dentry)
|
||||
goto out2; /* not a mountpoint */
|
||||
if (root.mnt->mnt_parent == root.mnt)
|
||||
goto out2; /* not attached */
|
||||
if (new_nd.path.mnt->mnt_root != new_nd.path.dentry)
|
||||
if (new.mnt->mnt_root != new.dentry)
|
||||
goto out2; /* not a mountpoint */
|
||||
if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt)
|
||||
if (new.mnt->mnt_parent == new.mnt)
|
||||
goto out2; /* not attached */
|
||||
/* make sure we can reach put_old from new_root */
|
||||
tmp = old_nd.path.mnt;
|
||||
tmp = old.mnt;
|
||||
spin_lock(&vfsmount_lock);
|
||||
if (tmp != new_nd.path.mnt) {
|
||||
if (tmp != new.mnt) {
|
||||
for (;;) {
|
||||
if (tmp->mnt_parent == tmp)
|
||||
goto out3; /* already mounted on put_old */
|
||||
if (tmp->mnt_parent == new_nd.path.mnt)
|
||||
if (tmp->mnt_parent == new.mnt)
|
||||
break;
|
||||
tmp = tmp->mnt_parent;
|
||||
}
|
||||
if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry))
|
||||
if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
|
||||
goto out3;
|
||||
} else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry))
|
||||
} else if (!is_subdir(old.dentry, new.dentry))
|
||||
goto out3;
|
||||
detach_mnt(new_nd.path.mnt, &parent_path);
|
||||
detach_mnt(new.mnt, &parent_path);
|
||||
detach_mnt(root.mnt, &root_parent);
|
||||
/* mount old root on put_old */
|
||||
attach_mnt(root.mnt, &old_nd.path);
|
||||
attach_mnt(root.mnt, &old);
|
||||
/* mount new_root on / */
|
||||
attach_mnt(new_nd.path.mnt, &root_parent);
|
||||
attach_mnt(new.mnt, &root_parent);
|
||||
touch_mnt_namespace(current->nsproxy->mnt_ns);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
chroot_fs_refs(&root, &new_nd.path);
|
||||
security_sb_post_pivotroot(&root, &new_nd.path);
|
||||
chroot_fs_refs(&root, &new);
|
||||
security_sb_post_pivotroot(&root, &new);
|
||||
error = 0;
|
||||
path_put(&root_parent);
|
||||
path_put(&parent_path);
|
||||
out2:
|
||||
mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex);
|
||||
mutex_unlock(&old.dentry->d_inode->i_mutex);
|
||||
up_write(&namespace_sem);
|
||||
path_put(&root);
|
||||
path_put(&old_nd.path);
|
||||
path_put(&old);
|
||||
out1:
|
||||
path_put(&new_nd.path);
|
||||
path_put(&new);
|
||||
out0:
|
||||
return error;
|
||||
out3:
|
||||
|
|
|
@ -266,7 +266,7 @@ leave_me:;
|
|||
|
||||
|
||||
static int
|
||||
__ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd)
|
||||
__ncp_lookup_validate(struct dentry *dentry)
|
||||
{
|
||||
struct ncp_server *server;
|
||||
struct dentry *parent;
|
||||
|
@ -340,7 +340,7 @@ ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd)
|
|||
{
|
||||
int res;
|
||||
lock_kernel();
|
||||
res = __ncp_lookup_validate(dentry, nd);
|
||||
res = __ncp_lookup_validate(dentry);
|
||||
unlock_kernel();
|
||||
return res;
|
||||
}
|
||||
|
|
11
fs/nfs/dir.c
11
fs/nfs/dir.c
|
@ -1884,7 +1884,7 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
|
|||
return status;
|
||||
nfs_access_add_cache(inode, &cache);
|
||||
out:
|
||||
if ((cache.mask & mask) == mask)
|
||||
if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
|
||||
return 0;
|
||||
return -EACCES;
|
||||
}
|
||||
|
@ -1907,17 +1907,17 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
|
|||
return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
|
||||
}
|
||||
|
||||
int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
int nfs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
struct rpc_cred *cred;
|
||||
int res = 0;
|
||||
|
||||
nfs_inc_stats(inode, NFSIOS_VFSACCESS);
|
||||
|
||||
if (mask == 0)
|
||||
if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
|
||||
goto out;
|
||||
/* Is this sys_access() ? */
|
||||
if (nd != NULL && (nd->flags & LOOKUP_ACCESS))
|
||||
if (mask & MAY_ACCESS)
|
||||
goto force_lookup;
|
||||
|
||||
switch (inode->i_mode & S_IFMT) {
|
||||
|
@ -1926,8 +1926,7 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
|
|||
case S_IFREG:
|
||||
/* NFSv4 has atomic_open... */
|
||||
if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN)
|
||||
&& nd != NULL
|
||||
&& (nd->flags & LOOKUP_OPEN))
|
||||
&& (mask & MAY_OPEN))
|
||||
goto out;
|
||||
break;
|
||||
case S_IFDIR:
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/time.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/in.h>
|
||||
|
|
|
@ -51,7 +51,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
|
|||
/* make sure parents give x permission to user */
|
||||
int err;
|
||||
parent = dget_parent(tdentry);
|
||||
err = permission(parent->d_inode, MAY_EXEC, NULL);
|
||||
err = inode_permission(parent->d_inode, MAY_EXEC);
|
||||
if (err < 0) {
|
||||
dput(parent);
|
||||
break;
|
||||
|
|
|
@ -1516,7 +1516,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||
struct dentry *dentry, *dnew;
|
||||
__be32 err, cerr;
|
||||
int host_err;
|
||||
umode_t mode;
|
||||
|
||||
err = nfserr_noent;
|
||||
if (!flen || !plen)
|
||||
|
@ -1535,11 +1534,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||
if (IS_ERR(dnew))
|
||||
goto out_nfserr;
|
||||
|
||||
mode = S_IALLUGO;
|
||||
/* Only the MODE ATTRibute is even vaguely meaningful */
|
||||
if (iap && (iap->ia_valid & ATTR_MODE))
|
||||
mode = iap->ia_mode & S_IALLUGO;
|
||||
|
||||
host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
@ -1551,11 +1545,11 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||
else {
|
||||
strncpy(path_alloced, path, plen);
|
||||
path_alloced[plen] = 0;
|
||||
host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);
|
||||
host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced);
|
||||
kfree(path_alloced);
|
||||
}
|
||||
} else
|
||||
host_err = vfs_symlink(dentry->d_inode, dnew, path, mode);
|
||||
host_err = vfs_symlink(dentry->d_inode, dnew, path);
|
||||
|
||||
if (!host_err) {
|
||||
if (EX_ISSYNC(fhp->fh_export))
|
||||
|
@ -1959,12 +1953,12 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
|
|||
return 0;
|
||||
|
||||
/* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
|
||||
err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL);
|
||||
err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));
|
||||
|
||||
/* Allow read access to binaries even when mode 111 */
|
||||
if (err == -EACCES && S_ISREG(inode->i_mode) &&
|
||||
acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
|
||||
err = permission(inode, MAY_EXEC, NULL);
|
||||
err = inode_permission(inode, MAY_EXEC);
|
||||
|
||||
return err? nfserrno(err) : 0;
|
||||
}
|
||||
|
|
|
@ -2118,7 +2118,7 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb,
|
|||
goto out;
|
||||
if (!count)
|
||||
goto out;
|
||||
err = remove_suid(file->f_path.dentry);
|
||||
err = file_remove_suid(file);
|
||||
if (err)
|
||||
goto out;
|
||||
file_update_time(file);
|
||||
|
|
|
@ -1176,7 +1176,7 @@ bail:
|
|||
return err;
|
||||
}
|
||||
|
||||
int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
int ocfs2_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
|
@ -62,8 +62,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
|
|||
int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat);
|
||||
int ocfs2_permission(struct inode *inode, int mask,
|
||||
struct nameidata *nd);
|
||||
int ocfs2_permission(struct inode *inode, int mask);
|
||||
|
||||
int ocfs2_should_update_atime(struct inode *inode,
|
||||
struct vfsmount *vfsmnt);
|
||||
|
|
179
fs/open.c
179
fs/open.c
|
@ -122,37 +122,37 @@ static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf)
|
||||
asmlinkage long sys_statfs(const char __user *pathname, struct statfs __user * buf)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (!error) {
|
||||
struct statfs tmp;
|
||||
error = vfs_statfs_native(nd.path.dentry, &tmp);
|
||||
error = vfs_statfs_native(path.dentry, &tmp);
|
||||
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
||||
error = -EFAULT;
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf)
|
||||
asmlinkage long sys_statfs64(const char __user *pathname, size_t sz, struct statfs64 __user *buf)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
long error;
|
||||
|
||||
if (sz != sizeof(*buf))
|
||||
return -EINVAL;
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (!error) {
|
||||
struct statfs64 tmp;
|
||||
error = vfs_statfs64(nd.path.dentry, &tmp);
|
||||
error = vfs_statfs64(path.dentry, &tmp);
|
||||
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
||||
error = -EFAULT;
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -223,20 +223,20 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
|||
return err;
|
||||
}
|
||||
|
||||
static long do_sys_truncate(const char __user * path, loff_t length)
|
||||
static long do_sys_truncate(const char __user *pathname, loff_t length)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct inode * inode;
|
||||
struct path path;
|
||||
struct inode *inode;
|
||||
int error;
|
||||
|
||||
error = -EINVAL;
|
||||
if (length < 0) /* sorry, but loff_t says... */
|
||||
goto out;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
inode = nd.path.dentry->d_inode;
|
||||
inode = path.dentry->d_inode;
|
||||
|
||||
/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
|
||||
error = -EISDIR;
|
||||
|
@ -247,16 +247,16 @@ static long do_sys_truncate(const char __user * path, loff_t length)
|
|||
if (!S_ISREG(inode->i_mode))
|
||||
goto dput_and_out;
|
||||
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
error = vfs_permission(&nd, MAY_WRITE);
|
||||
error = inode_permission(inode, MAY_WRITE);
|
||||
if (error)
|
||||
goto mnt_drop_write_and_out;
|
||||
|
||||
error = -EPERM;
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
if (IS_APPEND(inode))
|
||||
goto mnt_drop_write_and_out;
|
||||
|
||||
error = get_write_access(inode);
|
||||
|
@ -274,15 +274,15 @@ static long do_sys_truncate(const char __user * path, loff_t length)
|
|||
error = locks_verify_truncate(inode, NULL, length);
|
||||
if (!error) {
|
||||
DQUOT_INIT(inode);
|
||||
error = do_truncate(nd.path.dentry, length, 0, NULL);
|
||||
error = do_truncate(path.dentry, length, 0, NULL);
|
||||
}
|
||||
|
||||
put_write_and_out:
|
||||
put_write_access(inode);
|
||||
mnt_drop_write_and_out:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
mnt_drop_write(path.mnt);
|
||||
dput_and_out:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -425,7 +425,8 @@ out:
|
|||
*/
|
||||
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
struct inode *inode;
|
||||
int old_fsuid, old_fsgid;
|
||||
kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */
|
||||
int res;
|
||||
|
@ -448,7 +449,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
|||
* FIXME: There is a race here against sys_capset. The
|
||||
* capabilities can change yet we will restore the old
|
||||
* value below. We should hold task_capabilities_lock,
|
||||
* but we cannot because user_path_walk can sleep.
|
||||
* but we cannot because user_path_at can sleep.
|
||||
*/
|
||||
#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
|
||||
if (current->uid)
|
||||
|
@ -457,14 +458,25 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
|||
old_cap = cap_set_effective(current->cap_permitted);
|
||||
}
|
||||
|
||||
res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
|
||||
res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
res = vfs_permission(&nd, mode);
|
||||
inode = path.dentry->d_inode;
|
||||
|
||||
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
||||
/*
|
||||
* MAY_EXEC on regular files is denied if the fs is mounted
|
||||
* with the "noexec" flag.
|
||||
*/
|
||||
res = -EACCES;
|
||||
if (path.mnt->mnt_flags & MNT_NOEXEC)
|
||||
goto out_path_release;
|
||||
}
|
||||
|
||||
res = inode_permission(inode, mode | MAY_ACCESS);
|
||||
/* SuS v2 requires we report a read only fs too */
|
||||
if(res || !(mode & S_IWOTH) ||
|
||||
special_file(nd.path.dentry->d_inode->i_mode))
|
||||
if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
|
||||
goto out_path_release;
|
||||
/*
|
||||
* This is a rare case where using __mnt_is_readonly()
|
||||
|
@ -476,11 +488,11 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
|
|||
* inherently racy and know that the fs may change
|
||||
* state before we even see this result.
|
||||
*/
|
||||
if (__mnt_is_readonly(nd.path.mnt))
|
||||
if (__mnt_is_readonly(path.mnt))
|
||||
res = -EROFS;
|
||||
|
||||
out_path_release:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
current->fsuid = old_fsuid;
|
||||
current->fsgid = old_fsgid;
|
||||
|
@ -498,22 +510,21 @@ asmlinkage long sys_access(const char __user *filename, int mode)
|
|||
|
||||
asmlinkage long sys_chdir(const char __user * filename)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = __user_walk(filename,
|
||||
LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
|
||||
error = user_path_dir(filename, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = vfs_permission(&nd, MAY_EXEC);
|
||||
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
set_fs_pwd(current->fs, &nd.path);
|
||||
set_fs_pwd(current->fs, &path);
|
||||
|
||||
dput_and_out:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -535,7 +546,7 @@ asmlinkage long sys_fchdir(unsigned int fd)
|
|||
if (!S_ISDIR(inode->i_mode))
|
||||
goto out_putf;
|
||||
|
||||
error = file_permission(file, MAY_EXEC);
|
||||
error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
|
||||
if (!error)
|
||||
set_fs_pwd(current->fs, &file->f_path);
|
||||
out_putf:
|
||||
|
@ -546,14 +557,14 @@ out:
|
|||
|
||||
asmlinkage long sys_chroot(const char __user * filename)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
|
||||
error = user_path_dir(filename, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = vfs_permission(&nd, MAY_EXEC);
|
||||
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
|
@ -561,11 +572,10 @@ asmlinkage long sys_chroot(const char __user * filename)
|
|||
if (!capable(CAP_SYS_CHROOT))
|
||||
goto dput_and_out;
|
||||
|
||||
set_fs_root(current->fs, &nd.path);
|
||||
set_fs_altroot();
|
||||
set_fs_root(current->fs, &path);
|
||||
error = 0;
|
||||
dput_and_out:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -590,9 +600,6 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
|
|||
err = mnt_want_write(file->f_path.mnt);
|
||||
if (err)
|
||||
goto out_putf;
|
||||
err = -EPERM;
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
goto out_drop_write;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
if (mode == (mode_t) -1)
|
||||
mode = inode->i_mode;
|
||||
|
@ -600,8 +607,6 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
|
|||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
err = notify_change(dentry, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
out_drop_write:
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_putf:
|
||||
fput(file);
|
||||
|
@ -612,36 +617,29 @@ out:
|
|||
asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
|
||||
mode_t mode)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct inode * inode;
|
||||
struct path path;
|
||||
struct inode *inode;
|
||||
int error;
|
||||
struct iattr newattrs;
|
||||
|
||||
error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
|
||||
error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
inode = nd.path.dentry->d_inode;
|
||||
inode = path.dentry->d_inode;
|
||||
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
error = -EPERM;
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
goto out_drop_write;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
if (mode == (mode_t) -1)
|
||||
mode = inode->i_mode;
|
||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
error = notify_change(nd.path.dentry, &newattrs);
|
||||
error = notify_change(path.dentry, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
out_drop_write:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
mnt_drop_write(path.mnt);
|
||||
dput_and_out:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -653,18 +651,10 @@ asmlinkage long sys_chmod(const char __user *filename, mode_t mode)
|
|||
|
||||
static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
|
||||
{
|
||||
struct inode * inode;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
struct iattr newattrs;
|
||||
|
||||
error = -ENOENT;
|
||||
if (!(inode = dentry->d_inode)) {
|
||||
printk(KERN_ERR "chown_common: NULL inode\n");
|
||||
goto out;
|
||||
}
|
||||
error = -EPERM;
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
goto out;
|
||||
newattrs.ia_valid = ATTR_CTIME;
|
||||
if (user != (uid_t) -1) {
|
||||
newattrs.ia_valid |= ATTR_UID;
|
||||
|
@ -680,25 +670,25 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
|
|||
mutex_lock(&inode->i_mutex);
|
||||
error = notify_change(dentry, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
out:
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk(filename, &nd);
|
||||
error = user_path(filename, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
error = chown_common(nd.path.dentry, user, group);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
error = chown_common(path.dentry, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -706,7 +696,7 @@ out:
|
|||
asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
|
||||
gid_t group, int flag)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error = -EINVAL;
|
||||
int follow;
|
||||
|
||||
|
@ -714,35 +704,35 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
|
|||
goto out;
|
||||
|
||||
follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
|
||||
error = __user_walk_fd(dfd, filename, follow, &nd);
|
||||
error = user_path_at(dfd, filename, follow, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
error = chown_common(nd.path.dentry, user, group);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
error = chown_common(path.dentry, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk_link(filename, &nd);
|
||||
error = user_lpath(filename, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
error = chown_common(nd.path.dentry, user, group);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
error = chown_common(path.dentry, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -982,7 +972,6 @@ int get_unused_fd_flags(int flags)
|
|||
int fd, error;
|
||||
struct fdtable *fdt;
|
||||
|
||||
error = -EMFILE;
|
||||
spin_lock(&files->file_lock);
|
||||
|
||||
repeat:
|
||||
|
@ -990,13 +979,6 @@ repeat:
|
|||
fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
|
||||
files->next_fd);
|
||||
|
||||
/*
|
||||
* N.B. For clone tasks sharing a files structure, this test
|
||||
* will limit the total number of files that can be opened.
|
||||
*/
|
||||
if (fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||
goto out;
|
||||
|
||||
/* Do we need to expand the fd array or fd set? */
|
||||
error = expand_files(files, fd);
|
||||
if (error < 0)
|
||||
|
@ -1007,7 +989,6 @@ repeat:
|
|||
* If we needed to expand the fs array we
|
||||
* might have blocked - try again.
|
||||
*/
|
||||
error = -EMFILE;
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
|
|
51
fs/pipe.c
51
fs/pipe.c
|
@ -777,8 +777,10 @@ pipe_rdwr_open(struct inode *inode, struct file *filp)
|
|||
/*
|
||||
* The file_operations structs are not static because they
|
||||
* are also used in linux/fs/fifo.c to do operations on FIFOs.
|
||||
*
|
||||
* Pipes reuse fifos' file_operations structs.
|
||||
*/
|
||||
const struct file_operations read_fifo_fops = {
|
||||
const struct file_operations read_pipefifo_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = do_sync_read,
|
||||
.aio_read = pipe_read,
|
||||
|
@ -790,7 +792,7 @@ const struct file_operations read_fifo_fops = {
|
|||
.fasync = pipe_read_fasync,
|
||||
};
|
||||
|
||||
const struct file_operations write_fifo_fops = {
|
||||
const struct file_operations write_pipefifo_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = bad_pipe_r,
|
||||
.write = do_sync_write,
|
||||
|
@ -802,44 +804,7 @@ const struct file_operations write_fifo_fops = {
|
|||
.fasync = pipe_write_fasync,
|
||||
};
|
||||
|
||||
const struct file_operations rdwr_fifo_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = do_sync_read,
|
||||
.aio_read = pipe_read,
|
||||
.write = do_sync_write,
|
||||
.aio_write = pipe_write,
|
||||
.poll = pipe_poll,
|
||||
.unlocked_ioctl = pipe_ioctl,
|
||||
.open = pipe_rdwr_open,
|
||||
.release = pipe_rdwr_release,
|
||||
.fasync = pipe_rdwr_fasync,
|
||||
};
|
||||
|
||||
static const struct file_operations read_pipe_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = do_sync_read,
|
||||
.aio_read = pipe_read,
|
||||
.write = bad_pipe_w,
|
||||
.poll = pipe_poll,
|
||||
.unlocked_ioctl = pipe_ioctl,
|
||||
.open = pipe_read_open,
|
||||
.release = pipe_read_release,
|
||||
.fasync = pipe_read_fasync,
|
||||
};
|
||||
|
||||
static const struct file_operations write_pipe_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = bad_pipe_r,
|
||||
.write = do_sync_write,
|
||||
.aio_write = pipe_write,
|
||||
.poll = pipe_poll,
|
||||
.unlocked_ioctl = pipe_ioctl,
|
||||
.open = pipe_write_open,
|
||||
.release = pipe_write_release,
|
||||
.fasync = pipe_write_fasync,
|
||||
};
|
||||
|
||||
static const struct file_operations rdwr_pipe_fops = {
|
||||
const struct file_operations rdwr_pipefifo_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = do_sync_read,
|
||||
.aio_read = pipe_read,
|
||||
|
@ -927,7 +892,7 @@ static struct inode * get_pipe_inode(void)
|
|||
inode->i_pipe = pipe;
|
||||
|
||||
pipe->readers = pipe->writers = 1;
|
||||
inode->i_fop = &rdwr_pipe_fops;
|
||||
inode->i_fop = &rdwr_pipefifo_fops;
|
||||
|
||||
/*
|
||||
* Mark the inode dirty from the very beginning,
|
||||
|
@ -978,7 +943,7 @@ struct file *create_write_pipe(int flags)
|
|||
d_instantiate(dentry, inode);
|
||||
|
||||
err = -ENFILE;
|
||||
f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipe_fops);
|
||||
f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipefifo_fops);
|
||||
if (!f)
|
||||
goto err_dentry;
|
||||
f->f_mapping = inode->i_mapping;
|
||||
|
@ -1020,7 +985,7 @@ struct file *create_read_pipe(struct file *wrf, int flags)
|
|||
|
||||
f->f_pos = 0;
|
||||
f->f_flags = O_RDONLY | (flags & O_NONBLOCK);
|
||||
f->f_op = &read_pipe_fops;
|
||||
f->f_op = &read_pipefifo_fops;
|
||||
f->f_mode = FMODE_READ;
|
||||
f->f_version = 0;
|
||||
|
||||
|
|
|
@ -1859,8 +1859,7 @@ static const struct file_operations proc_fd_operations = {
|
|||
* /proc/pid/fd needs a special permission handler so that a process can still
|
||||
* access /proc/self/fd after it has executed a setuid().
|
||||
*/
|
||||
static int proc_fd_permission(struct inode *inode, int mask,
|
||||
struct nameidata *nd)
|
||||
static int proc_fd_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int rv;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/sysctl.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -65,6 +66,8 @@ static void proc_delete_inode(struct inode *inode)
|
|||
module_put(de->owner);
|
||||
de_put(de);
|
||||
}
|
||||
if (PROC_I(inode)->sysctl)
|
||||
sysctl_head_put(PROC_I(inode)->sysctl);
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
|
@ -84,6 +87,8 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
|
|||
ei->fd = 0;
|
||||
ei->op.proc_get_link = NULL;
|
||||
ei->pde = NULL;
|
||||
ei->sysctl = NULL;
|
||||
ei->sysctl_entry = NULL;
|
||||
inode = &ei->vfs_inode;
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
||||
return inode;
|
||||
|
|
|
@ -10,149 +10,110 @@
|
|||
static struct dentry_operations proc_sys_dentry_operations;
|
||||
static const struct file_operations proc_sys_file_operations;
|
||||
static const struct inode_operations proc_sys_inode_operations;
|
||||
static const struct file_operations proc_sys_dir_file_operations;
|
||||
static const struct inode_operations proc_sys_dir_operations;
|
||||
|
||||
static void proc_sys_refresh_inode(struct inode *inode, struct ctl_table *table)
|
||||
{
|
||||
/* Refresh the cached information bits in the inode */
|
||||
if (table) {
|
||||
inode->i_uid = 0;
|
||||
inode->i_gid = 0;
|
||||
inode->i_mode = table->mode;
|
||||
if (table->proc_handler) {
|
||||
inode->i_mode |= S_IFREG;
|
||||
inode->i_nlink = 1;
|
||||
} else {
|
||||
inode->i_mode |= S_IFDIR;
|
||||
inode->i_nlink = 0; /* It is too hard to figure out */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct inode *proc_sys_make_inode(struct inode *dir, struct ctl_table *table)
|
||||
static struct inode *proc_sys_make_inode(struct super_block *sb,
|
||||
struct ctl_table_header *head, struct ctl_table *table)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct proc_inode *dir_ei, *ei;
|
||||
int depth;
|
||||
struct proc_inode *ei;
|
||||
|
||||
inode = new_inode(dir->i_sb);
|
||||
inode = new_inode(sb);
|
||||
if (!inode)
|
||||
goto out;
|
||||
|
||||
/* A directory is always one deeper than it's parent */
|
||||
dir_ei = PROC_I(dir);
|
||||
depth = dir_ei->fd + 1;
|
||||
|
||||
sysctl_head_get(head);
|
||||
ei = PROC_I(inode);
|
||||
ei->fd = depth;
|
||||
ei->sysctl = head;
|
||||
ei->sysctl_entry = table;
|
||||
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
||||
inode->i_op = &proc_sys_inode_operations;
|
||||
inode->i_fop = &proc_sys_file_operations;
|
||||
inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */
|
||||
proc_sys_refresh_inode(inode, table);
|
||||
inode->i_mode = table->mode;
|
||||
if (!table->child) {
|
||||
inode->i_mode |= S_IFREG;
|
||||
inode->i_op = &proc_sys_inode_operations;
|
||||
inode->i_fop = &proc_sys_file_operations;
|
||||
} else {
|
||||
inode->i_mode |= S_IFDIR;
|
||||
inode->i_nlink = 0;
|
||||
inode->i_op = &proc_sys_dir_operations;
|
||||
inode->i_fop = &proc_sys_dir_file_operations;
|
||||
}
|
||||
out:
|
||||
return inode;
|
||||
}
|
||||
|
||||
static struct dentry *proc_sys_ancestor(struct dentry *dentry, int depth)
|
||||
{
|
||||
for (;;) {
|
||||
struct proc_inode *ei;
|
||||
|
||||
ei = PROC_I(dentry->d_inode);
|
||||
if (ei->fd == depth)
|
||||
break; /* found */
|
||||
|
||||
dentry = dentry->d_parent;
|
||||
}
|
||||
return dentry;
|
||||
}
|
||||
|
||||
static struct ctl_table *proc_sys_lookup_table_one(struct ctl_table *table,
|
||||
struct qstr *name)
|
||||
static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
|
||||
{
|
||||
int len;
|
||||
for ( ; table->ctl_name || table->procname; table++) {
|
||||
for ( ; p->ctl_name || p->procname; p++) {
|
||||
|
||||
if (!table->procname)
|
||||
if (!p->procname)
|
||||
continue;
|
||||
|
||||
len = strlen(table->procname);
|
||||
len = strlen(p->procname);
|
||||
if (len != name->len)
|
||||
continue;
|
||||
|
||||
if (memcmp(table->procname, name->name, len) != 0)
|
||||
if (memcmp(p->procname, name->name, len) != 0)
|
||||
continue;
|
||||
|
||||
/* I have a match */
|
||||
return table;
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ctl_table *proc_sys_lookup_table(struct dentry *dentry,
|
||||
struct ctl_table *table)
|
||||
struct ctl_table_header *grab_header(struct inode *inode)
|
||||
{
|
||||
struct dentry *ancestor;
|
||||
struct proc_inode *ei;
|
||||
int depth, i;
|
||||
|
||||
ei = PROC_I(dentry->d_inode);
|
||||
depth = ei->fd;
|
||||
|
||||
if (depth == 0)
|
||||
return table;
|
||||
|
||||
for (i = 1; table && (i <= depth); i++) {
|
||||
ancestor = proc_sys_ancestor(dentry, i);
|
||||
table = proc_sys_lookup_table_one(table, &ancestor->d_name);
|
||||
if (table)
|
||||
table = table->child;
|
||||
}
|
||||
return table;
|
||||
|
||||
}
|
||||
static struct ctl_table *proc_sys_lookup_entry(struct dentry *dparent,
|
||||
struct qstr *name,
|
||||
struct ctl_table *table)
|
||||
{
|
||||
table = proc_sys_lookup_table(dparent, table);
|
||||
if (table)
|
||||
table = proc_sys_lookup_table_one(table, name);
|
||||
return table;
|
||||
}
|
||||
|
||||
static struct ctl_table *do_proc_sys_lookup(struct dentry *parent,
|
||||
struct qstr *name,
|
||||
struct ctl_table_header **ptr)
|
||||
{
|
||||
struct ctl_table_header *head;
|
||||
struct ctl_table *table = NULL;
|
||||
|
||||
for (head = sysctl_head_next(NULL); head;
|
||||
head = sysctl_head_next(head)) {
|
||||
table = proc_sys_lookup_entry(parent, name, head->ctl_table);
|
||||
if (table)
|
||||
break;
|
||||
}
|
||||
*ptr = head;
|
||||
return table;
|
||||
if (PROC_I(inode)->sysctl)
|
||||
return sysctl_head_grab(PROC_I(inode)->sysctl);
|
||||
else
|
||||
return sysctl_head_next(NULL);
|
||||
}
|
||||
|
||||
static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
{
|
||||
struct ctl_table_header *head;
|
||||
struct ctl_table_header *head = grab_header(dir);
|
||||
struct ctl_table *table = PROC_I(dir)->sysctl_entry;
|
||||
struct ctl_table_header *h = NULL;
|
||||
struct qstr *name = &dentry->d_name;
|
||||
struct ctl_table *p;
|
||||
struct inode *inode;
|
||||
struct dentry *err;
|
||||
struct ctl_table *table;
|
||||
struct dentry *err = ERR_PTR(-ENOENT);
|
||||
|
||||
err = ERR_PTR(-ENOENT);
|
||||
table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
|
||||
if (!table)
|
||||
if (IS_ERR(head))
|
||||
return ERR_CAST(head);
|
||||
|
||||
if (table && !table->child) {
|
||||
WARN_ON(1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
table = table ? table->child : head->ctl_table;
|
||||
|
||||
p = find_in_table(table, name);
|
||||
if (!p) {
|
||||
for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
|
||||
if (h->attached_to != table)
|
||||
continue;
|
||||
p = find_in_table(h->attached_by, name);
|
||||
if (p)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!p)
|
||||
goto out;
|
||||
|
||||
err = ERR_PTR(-ENOMEM);
|
||||
inode = proc_sys_make_inode(dir, table);
|
||||
inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
|
||||
if (h)
|
||||
sysctl_head_finish(h);
|
||||
|
||||
if (!inode)
|
||||
goto out;
|
||||
|
||||
|
@ -168,22 +129,14 @@ out:
|
|||
static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
|
||||
size_t count, loff_t *ppos, int write)
|
||||
{
|
||||
struct dentry *dentry = filp->f_dentry;
|
||||
struct ctl_table_header *head;
|
||||
struct ctl_table *table;
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
struct ctl_table_header *head = grab_header(inode);
|
||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
||||
ssize_t error;
|
||||
size_t res;
|
||||
|
||||
table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
|
||||
/* Has the sysctl entry disappeared on us? */
|
||||
error = -ENOENT;
|
||||
if (!table)
|
||||
goto out;
|
||||
|
||||
/* Has the sysctl entry been replaced by a directory? */
|
||||
error = -EISDIR;
|
||||
if (!table->proc_handler)
|
||||
goto out;
|
||||
if (IS_ERR(head))
|
||||
return PTR_ERR(head);
|
||||
|
||||
/*
|
||||
* At this point we know that the sysctl was not unregistered
|
||||
|
@ -193,6 +146,11 @@ static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
|
|||
if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ))
|
||||
goto out;
|
||||
|
||||
/* if that can happen at all, it should be -EINVAL, not -EISDIR */
|
||||
error = -EINVAL;
|
||||
if (!table->proc_handler)
|
||||
goto out;
|
||||
|
||||
/* careful: calling conventions are nasty here */
|
||||
res = count;
|
||||
error = table->proc_handler(table, write, filp, buf, &res, ppos);
|
||||
|
@ -218,82 +176,86 @@ static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
|
|||
|
||||
|
||||
static int proc_sys_fill_cache(struct file *filp, void *dirent,
|
||||
filldir_t filldir, struct ctl_table *table)
|
||||
filldir_t filldir,
|
||||
struct ctl_table_header *head,
|
||||
struct ctl_table *table)
|
||||
{
|
||||
struct ctl_table_header *head;
|
||||
struct ctl_table *child_table = NULL;
|
||||
struct dentry *child, *dir = filp->f_path.dentry;
|
||||
struct inode *inode;
|
||||
struct qstr qname;
|
||||
ino_t ino = 0;
|
||||
unsigned type = DT_UNKNOWN;
|
||||
int ret;
|
||||
|
||||
qname.name = table->procname;
|
||||
qname.len = strlen(table->procname);
|
||||
qname.hash = full_name_hash(qname.name, qname.len);
|
||||
|
||||
/* Suppress duplicates.
|
||||
* Only fill a directory entry if it is the value that
|
||||
* an ordinary lookup of that name returns. Hide all
|
||||
* others.
|
||||
*
|
||||
* If we ever cache this translation in the dcache
|
||||
* I should do a dcache lookup first. But for now
|
||||
* it is just simpler not to.
|
||||
*/
|
||||
ret = 0;
|
||||
child_table = do_proc_sys_lookup(dir, &qname, &head);
|
||||
sysctl_head_finish(head);
|
||||
if (child_table != table)
|
||||
return 0;
|
||||
|
||||
child = d_lookup(dir, &qname);
|
||||
if (!child) {
|
||||
struct dentry *new;
|
||||
new = d_alloc(dir, &qname);
|
||||
if (new) {
|
||||
inode = proc_sys_make_inode(dir->d_inode, table);
|
||||
if (!inode)
|
||||
child = ERR_PTR(-ENOMEM);
|
||||
else {
|
||||
new->d_op = &proc_sys_dentry_operations;
|
||||
d_add(new, inode);
|
||||
child = d_alloc(dir, &qname);
|
||||
if (child) {
|
||||
inode = proc_sys_make_inode(dir->d_sb, head, table);
|
||||
if (!inode) {
|
||||
dput(child);
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
child->d_op = &proc_sys_dentry_operations;
|
||||
d_add(child, inode);
|
||||
}
|
||||
if (child)
|
||||
dput(new);
|
||||
else
|
||||
child = new;
|
||||
} else {
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
if (!child || IS_ERR(child) || !child->d_inode)
|
||||
goto end_instantiate;
|
||||
inode = child->d_inode;
|
||||
if (inode) {
|
||||
ino = inode->i_ino;
|
||||
type = inode->i_mode >> 12;
|
||||
}
|
||||
ino = inode->i_ino;
|
||||
type = inode->i_mode >> 12;
|
||||
dput(child);
|
||||
end_instantiate:
|
||||
if (!ino)
|
||||
ino= find_inode_number(dir, &qname);
|
||||
if (!ino)
|
||||
ino = 1;
|
||||
return filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
|
||||
return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
|
||||
}
|
||||
|
||||
static int scan(struct ctl_table_header *head, ctl_table *table,
|
||||
unsigned long *pos, struct file *file,
|
||||
void *dirent, filldir_t filldir)
|
||||
{
|
||||
|
||||
for (; table->ctl_name || table->procname; table++, (*pos)++) {
|
||||
int res;
|
||||
|
||||
/* Can't do anything without a proc name */
|
||||
if (!table->procname)
|
||||
continue;
|
||||
|
||||
if (*pos < file->f_pos)
|
||||
continue;
|
||||
|
||||
res = proc_sys_fill_cache(file, dirent, filldir, head, table);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
file->f_pos = *pos + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
{
|
||||
struct dentry *dentry = filp->f_dentry;
|
||||
struct dentry *dentry = filp->f_path.dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct ctl_table_header *head = NULL;
|
||||
struct ctl_table *table;
|
||||
struct ctl_table_header *head = grab_header(inode);
|
||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
||||
struct ctl_table_header *h = NULL;
|
||||
unsigned long pos;
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
|
||||
ret = -ENOTDIR;
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
if (IS_ERR(head))
|
||||
return PTR_ERR(head);
|
||||
|
||||
if (table && !table->child) {
|
||||
WARN_ON(1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
table = table ? table->child : head->ctl_table;
|
||||
|
||||
ret = 0;
|
||||
/* Avoid a switch here: arm builds fail with missing __cmpdi2 */
|
||||
|
@ -311,30 +273,17 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||
}
|
||||
pos = 2;
|
||||
|
||||
/* - Find each instance of the directory
|
||||
* - Read all entries in each instance
|
||||
* - Before returning an entry to user space lookup the entry
|
||||
* by name and if I find a different entry don't return
|
||||
* this one because it means it is a buried dup.
|
||||
* For sysctl this should only happen for directory entries.
|
||||
*/
|
||||
for (head = sysctl_head_next(NULL); head; head = sysctl_head_next(head)) {
|
||||
table = proc_sys_lookup_table(dentry, head->ctl_table);
|
||||
ret = scan(head, table, &pos, filp, dirent, filldir);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!table)
|
||||
for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
|
||||
if (h->attached_to != table)
|
||||
continue;
|
||||
|
||||
for (; table->ctl_name || table->procname; table++, pos++) {
|
||||
/* Can't do anything without a proc name */
|
||||
if (!table->procname)
|
||||
continue;
|
||||
|
||||
if (pos < filp->f_pos)
|
||||
continue;
|
||||
|
||||
if (proc_sys_fill_cache(filp, dirent, filldir, table) < 0)
|
||||
goto out;
|
||||
filp->f_pos = pos + 1;
|
||||
ret = scan(h, h->attached_by, &pos, filp, dirent, filldir);
|
||||
if (ret) {
|
||||
sysctl_head_finish(h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = 1;
|
||||
|
@ -343,53 +292,24 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
static int proc_sys_permission(struct inode *inode, int mask)
|
||||
{
|
||||
/*
|
||||
* sysctl entries that are not writeable,
|
||||
* are _NOT_ writeable, capabilities or not.
|
||||
*/
|
||||
struct ctl_table_header *head;
|
||||
struct ctl_table *table;
|
||||
struct dentry *dentry;
|
||||
int mode;
|
||||
int depth;
|
||||
struct ctl_table_header *head = grab_header(inode);
|
||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
||||
int error;
|
||||
|
||||
head = NULL;
|
||||
depth = PROC_I(inode)->fd;
|
||||
if (IS_ERR(head))
|
||||
return PTR_ERR(head);
|
||||
|
||||
/* First check the cached permissions, in case we don't have
|
||||
* enough information to lookup the sysctl table entry.
|
||||
*/
|
||||
error = -EACCES;
|
||||
mode = inode->i_mode;
|
||||
if (!table) /* global root - r-xr-xr-x */
|
||||
error = mask & MAY_WRITE ? -EACCES : 0;
|
||||
else /* Use the permissions on the sysctl table entry */
|
||||
error = sysctl_perm(head->root, table, mask);
|
||||
|
||||
if (current->euid == 0)
|
||||
mode >>= 6;
|
||||
else if (in_group_p(0))
|
||||
mode >>= 3;
|
||||
|
||||
if ((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask)
|
||||
error = 0;
|
||||
|
||||
/* If we can't get a sysctl table entry the permission
|
||||
* checks on the cached mode will have to be enough.
|
||||
*/
|
||||
if (!nd || !depth)
|
||||
goto out;
|
||||
|
||||
dentry = nd->path.dentry;
|
||||
table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
|
||||
|
||||
/* If the entry does not exist deny permission */
|
||||
error = -EACCES;
|
||||
if (!table)
|
||||
goto out;
|
||||
|
||||
/* Use the permissions on the sysctl table entry */
|
||||
error = sysctl_perm(head->root, table, mask);
|
||||
out:
|
||||
sysctl_head_finish(head);
|
||||
return error;
|
||||
}
|
||||
|
@ -409,33 +329,70 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
return error;
|
||||
}
|
||||
|
||||
/* I'm lazy and don't distinguish between files and directories,
|
||||
* until access time.
|
||||
*/
|
||||
static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct ctl_table_header *head = grab_header(inode);
|
||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
||||
|
||||
if (IS_ERR(head))
|
||||
return PTR_ERR(head);
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
if (table)
|
||||
stat->mode = (stat->mode & S_IFMT) | table->mode;
|
||||
|
||||
sysctl_head_finish(head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations proc_sys_file_operations = {
|
||||
.read = proc_sys_read,
|
||||
.write = proc_sys_write,
|
||||
};
|
||||
|
||||
static const struct file_operations proc_sys_dir_file_operations = {
|
||||
.readdir = proc_sys_readdir,
|
||||
};
|
||||
|
||||
static const struct inode_operations proc_sys_inode_operations = {
|
||||
.permission = proc_sys_permission,
|
||||
.setattr = proc_sys_setattr,
|
||||
.getattr = proc_sys_getattr,
|
||||
};
|
||||
|
||||
static const struct inode_operations proc_sys_dir_operations = {
|
||||
.lookup = proc_sys_lookup,
|
||||
.permission = proc_sys_permission,
|
||||
.setattr = proc_sys_setattr,
|
||||
.getattr = proc_sys_getattr,
|
||||
};
|
||||
|
||||
static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct ctl_table_header *head;
|
||||
struct ctl_table *table;
|
||||
table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
|
||||
proc_sys_refresh_inode(dentry->d_inode, table);
|
||||
sysctl_head_finish(head);
|
||||
return !!table;
|
||||
return !PROC_I(dentry->d_inode)->sysctl->unregistering;
|
||||
}
|
||||
|
||||
static int proc_sys_delete(struct dentry *dentry)
|
||||
{
|
||||
return !!PROC_I(dentry->d_inode)->sysctl->unregistering;
|
||||
}
|
||||
|
||||
static int proc_sys_compare(struct dentry *dir, struct qstr *qstr,
|
||||
struct qstr *name)
|
||||
{
|
||||
struct dentry *dentry = container_of(qstr, struct dentry, d_name);
|
||||
if (qstr->len != name->len)
|
||||
return 1;
|
||||
if (memcmp(qstr->name, name->name, name->len))
|
||||
return 1;
|
||||
return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl);
|
||||
}
|
||||
|
||||
static struct dentry_operations proc_sys_dentry_operations = {
|
||||
.d_revalidate = proc_sys_revalidate,
|
||||
.d_delete = proc_sys_delete,
|
||||
.d_compare = proc_sys_compare,
|
||||
};
|
||||
|
||||
static struct proc_dir_entry *proc_sys_root;
|
||||
|
@ -443,8 +400,8 @@ static struct proc_dir_entry *proc_sys_root;
|
|||
int proc_sys_init(void)
|
||||
{
|
||||
proc_sys_root = proc_mkdir("sys", NULL);
|
||||
proc_sys_root->proc_iops = &proc_sys_inode_operations;
|
||||
proc_sys_root->proc_fops = &proc_sys_file_operations;
|
||||
proc_sys_root->proc_iops = &proc_sys_dir_operations;
|
||||
proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
|
||||
proc_sys_root->nlink = 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1250,7 +1250,7 @@ static int reiserfs_check_acl(struct inode *inode, int mask)
|
|||
return error;
|
||||
}
|
||||
|
||||
int reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
int reiserfs_permission(struct inode *inode, int mask)
|
||||
{
|
||||
/*
|
||||
* We don't do permission checks on the internal objects.
|
||||
|
|
|
@ -408,7 +408,7 @@ smb_file_release(struct inode *inode, struct file * file)
|
|||
* privileges, so we need our own check for this.
|
||||
*/
|
||||
static int
|
||||
smb_file_permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
smb_file_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int mode = inode->i_mode;
|
||||
int error = 0;
|
||||
|
@ -417,7 +417,7 @@ smb_file_permission(struct inode *inode, int mask, struct nameidata *nd)
|
|||
|
||||
/* Look at user permissions */
|
||||
mode >>= 6;
|
||||
if ((mode & 7 & mask) != mask)
|
||||
if (mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC))
|
||||
error = -EACCES;
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -772,7 +772,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
|
|||
ssize_t ret;
|
||||
int err;
|
||||
|
||||
err = remove_suid(out->f_path.dentry);
|
||||
err = file_remove_suid(out);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
|
@ -830,7 +830,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
|
|||
ssize_t ret;
|
||||
|
||||
inode_double_lock(inode, pipe->inode);
|
||||
ret = remove_suid(out->f_path.dentry);
|
||||
ret = file_remove_suid(out);
|
||||
if (likely(!ret))
|
||||
ret = __splice_from_pipe(pipe, &sd, pipe_to_file);
|
||||
inode_double_unlock(inode, pipe->inode);
|
||||
|
|
32
fs/stat.c
32
fs/stat.c
|
@ -57,13 +57,13 @@ EXPORT_SYMBOL(vfs_getattr);
|
|||
|
||||
int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd);
|
||||
error = user_path_at(dfd, name, LOOKUP_FOLLOW, &path);
|
||||
if (!error) {
|
||||
error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat);
|
||||
path_put(&nd.path);
|
||||
error = vfs_getattr(path.mnt, path.dentry, stat);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -77,13 +77,13 @@ EXPORT_SYMBOL(vfs_stat);
|
|||
|
||||
int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = __user_walk_fd(dfd, name, 0, &nd);
|
||||
error = user_path_at(dfd, name, 0, &path);
|
||||
if (!error) {
|
||||
error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat);
|
||||
path_put(&nd.path);
|
||||
error = vfs_getattr(path.mnt, path.dentry, stat);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -291,29 +291,29 @@ asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf)
|
|||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long sys_readlinkat(int dfd, const char __user *path,
|
||||
asmlinkage long sys_readlinkat(int dfd, const char __user *pathname,
|
||||
char __user *buf, int bufsiz)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
if (bufsiz <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
error = __user_walk_fd(dfd, path, 0, &nd);
|
||||
error = user_path_at(dfd, pathname, 0, &path);
|
||||
if (!error) {
|
||||
struct inode *inode = nd.path.dentry->d_inode;
|
||||
struct inode *inode = path.dentry->d_inode;
|
||||
|
||||
error = -EINVAL;
|
||||
if (inode->i_op && inode->i_op->readlink) {
|
||||
error = security_inode_readlink(nd.path.dentry);
|
||||
error = security_inode_readlink(path.dentry);
|
||||
if (!error) {
|
||||
touch_atime(nd.path.mnt, nd.path.dentry);
|
||||
error = inode->i_op->readlink(nd.path.dentry,
|
||||
touch_atime(path.mnt, path.dentry);
|
||||
error = inode->i_op->readlink(path.dentry,
|
||||
buf, bufsiz);
|
||||
}
|
||||
}
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
#include "ubifs.h"
|
||||
#include <linux/mount.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
static int read_block(struct inode *inode, void *addr, unsigned int block,
|
||||
struct ubifs_data_node *dn)
|
||||
|
|
139
fs/utimes.c
139
fs/utimes.c
|
@ -48,66 +48,22 @@ static bool nsec_valid(long nsec)
|
|||
return nsec >= 0 && nsec <= 999999999;
|
||||
}
|
||||
|
||||
/* If times==NULL, set access and modification to current time,
|
||||
* must be owner or have write permission.
|
||||
* Else, update from *times, must be owner or super user.
|
||||
*/
|
||||
long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
|
||||
static int utimes_common(struct path *path, struct timespec *times)
|
||||
{
|
||||
int error;
|
||||
struct nameidata nd;
|
||||
struct dentry *dentry;
|
||||
struct inode *inode;
|
||||
struct iattr newattrs;
|
||||
struct file *f = NULL;
|
||||
struct vfsmount *mnt;
|
||||
struct inode *inode = path->dentry->d_inode;
|
||||
|
||||
error = -EINVAL;
|
||||
if (times && (!nsec_valid(times[0].tv_nsec) ||
|
||||
!nsec_valid(times[1].tv_nsec))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & ~AT_SYMLINK_NOFOLLOW)
|
||||
goto out;
|
||||
|
||||
if (filename == NULL && dfd != AT_FDCWD) {
|
||||
error = -EINVAL;
|
||||
if (flags & AT_SYMLINK_NOFOLLOW)
|
||||
goto out;
|
||||
|
||||
error = -EBADF;
|
||||
f = fget(dfd);
|
||||
if (!f)
|
||||
goto out;
|
||||
dentry = f->f_path.dentry;
|
||||
mnt = f->f_path.mnt;
|
||||
} else {
|
||||
error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
dentry = nd.path.dentry;
|
||||
mnt = nd.path.mnt;
|
||||
}
|
||||
|
||||
inode = dentry->d_inode;
|
||||
|
||||
error = mnt_want_write(mnt);
|
||||
error = mnt_want_write(path->mnt);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
goto out;
|
||||
|
||||
if (times && times[0].tv_nsec == UTIME_NOW &&
|
||||
times[1].tv_nsec == UTIME_NOW)
|
||||
times = NULL;
|
||||
|
||||
/* In most cases, the checks are done in inode_change_ok() */
|
||||
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
|
||||
if (times) {
|
||||
error = -EPERM;
|
||||
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
|
||||
goto mnt_drop_write_and_out;
|
||||
|
||||
if (times[0].tv_nsec == UTIME_OMIT)
|
||||
newattrs.ia_valid &= ~ATTR_ATIME;
|
||||
else if (times[0].tv_nsec != UTIME_NOW) {
|
||||
|
@ -123,21 +79,13 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
|
|||
newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
|
||||
newattrs.ia_valid |= ATTR_MTIME_SET;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the UTIME_OMIT/UTIME_NOW and UTIME_NOW/UTIME_OMIT
|
||||
* cases, we need to make an extra check that is not done by
|
||||
* inode_change_ok().
|
||||
* Tell inode_change_ok(), that this is an explicit time
|
||||
* update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
|
||||
* were used.
|
||||
*/
|
||||
if (((times[0].tv_nsec == UTIME_NOW &&
|
||||
times[1].tv_nsec == UTIME_OMIT)
|
||||
||
|
||||
(times[0].tv_nsec == UTIME_OMIT &&
|
||||
times[1].tv_nsec == UTIME_NOW))
|
||||
&& !is_owner_or_cap(inode))
|
||||
goto mnt_drop_write_and_out;
|
||||
newattrs.ia_valid |= ATTR_TIMES_SET;
|
||||
} else {
|
||||
|
||||
/*
|
||||
* If times is NULL (or both times are UTIME_NOW),
|
||||
* then we need to check permissions, because
|
||||
|
@ -148,21 +96,76 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
|
|||
goto mnt_drop_write_and_out;
|
||||
|
||||
if (!is_owner_or_cap(inode)) {
|
||||
error = permission(inode, MAY_WRITE, NULL);
|
||||
error = inode_permission(inode, MAY_WRITE);
|
||||
if (error)
|
||||
goto mnt_drop_write_and_out;
|
||||
}
|
||||
}
|
||||
mutex_lock(&inode->i_mutex);
|
||||
error = notify_change(dentry, &newattrs);
|
||||
error = notify_change(path->dentry, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
mnt_drop_write_and_out:
|
||||
mnt_drop_write(mnt);
|
||||
dput_and_out:
|
||||
if (f)
|
||||
fput(f);
|
||||
else
|
||||
path_put(&nd.path);
|
||||
mnt_drop_write(path->mnt);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_utimes - change times on filename or file descriptor
|
||||
* @dfd: open file descriptor, -1 or AT_FDCWD
|
||||
* @filename: path name or NULL
|
||||
* @times: new times or NULL
|
||||
* @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment)
|
||||
*
|
||||
* If filename is NULL and dfd refers to an open file, then operate on
|
||||
* the file. Otherwise look up filename, possibly using dfd as a
|
||||
* starting point.
|
||||
*
|
||||
* If times==NULL, set access and modification to current time,
|
||||
* must be owner or have write permission.
|
||||
* Else, update from *times, must be owner or super user.
|
||||
*/
|
||||
long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
|
||||
{
|
||||
int error = -EINVAL;
|
||||
|
||||
if (times && (!nsec_valid(times[0].tv_nsec) ||
|
||||
!nsec_valid(times[1].tv_nsec))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & ~AT_SYMLINK_NOFOLLOW)
|
||||
goto out;
|
||||
|
||||
if (filename == NULL && dfd != AT_FDCWD) {
|
||||
struct file *file;
|
||||
|
||||
if (flags & AT_SYMLINK_NOFOLLOW)
|
||||
goto out;
|
||||
|
||||
file = fget(dfd);
|
||||
error = -EBADF;
|
||||
if (!file)
|
||||
goto out;
|
||||
|
||||
error = utimes_common(&file->f_path, times);
|
||||
fput(file);
|
||||
} else {
|
||||
struct path path;
|
||||
int lookup_flags = 0;
|
||||
|
||||
if (!(flags & AT_SYMLINK_NOFOLLOW))
|
||||
lookup_flags |= LOOKUP_FOLLOW;
|
||||
|
||||
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = utimes_common(&path, times);
|
||||
path_put(&path);
|
||||
}
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
|
98
fs/xattr.c
98
fs/xattr.c
|
@ -63,7 +63,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
return permission(inode, mask, NULL);
|
||||
return inode_permission(inode, mask);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -252,40 +252,40 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
|
|||
}
|
||||
|
||||
asmlinkage long
|
||||
sys_setxattr(const char __user *path, const char __user *name,
|
||||
sys_setxattr(const char __user *pathname, const char __user *name,
|
||||
const void __user *value, size_t size, int flags)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
error = setxattr(nd.path.dentry, name, value, size, flags);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
error = setxattr(path.dentry, name, value, size, flags);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long
|
||||
sys_lsetxattr(const char __user *path, const char __user *name,
|
||||
sys_lsetxattr(const char __user *pathname, const char __user *name,
|
||||
const void __user *value, size_t size, int flags)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk_link(path, &nd);
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
error = setxattr(nd.path.dentry, name, value, size, flags);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
error = setxattr(path.dentry, name, value, size, flags);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -350,32 +350,32 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
|
|||
}
|
||||
|
||||
asmlinkage ssize_t
|
||||
sys_getxattr(const char __user *path, const char __user *name,
|
||||
sys_getxattr(const char __user *pathname, const char __user *name,
|
||||
void __user *value, size_t size)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
ssize_t error;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
error = getxattr(nd.path.dentry, name, value, size);
|
||||
path_put(&nd.path);
|
||||
error = getxattr(path.dentry, name, value, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage ssize_t
|
||||
sys_lgetxattr(const char __user *path, const char __user *name, void __user *value,
|
||||
sys_lgetxattr(const char __user *pathname, const char __user *name, void __user *value,
|
||||
size_t size)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
ssize_t error;
|
||||
|
||||
error = user_path_walk_link(path, &nd);
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
error = getxattr(nd.path.dentry, name, value, size);
|
||||
path_put(&nd.path);
|
||||
error = getxattr(path.dentry, name, value, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -425,30 +425,30 @@ listxattr(struct dentry *d, char __user *list, size_t size)
|
|||
}
|
||||
|
||||
asmlinkage ssize_t
|
||||
sys_listxattr(const char __user *path, char __user *list, size_t size)
|
||||
sys_listxattr(const char __user *pathname, char __user *list, size_t size)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
ssize_t error;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
error = listxattr(nd.path.dentry, list, size);
|
||||
path_put(&nd.path);
|
||||
error = listxattr(path.dentry, list, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage ssize_t
|
||||
sys_llistxattr(const char __user *path, char __user *list, size_t size)
|
||||
sys_llistxattr(const char __user *pathname, char __user *list, size_t size)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
ssize_t error;
|
||||
|
||||
error = user_path_walk_link(path, &nd);
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
error = listxattr(nd.path.dentry, list, size);
|
||||
path_put(&nd.path);
|
||||
error = listxattr(path.dentry, list, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -486,38 +486,38 @@ removexattr(struct dentry *d, const char __user *name)
|
|||
}
|
||||
|
||||
asmlinkage long
|
||||
sys_removexattr(const char __user *path, const char __user *name)
|
||||
sys_removexattr(const char __user *pathname, const char __user *name)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk(path, &nd);
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
error = removexattr(nd.path.dentry, name);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
error = removexattr(path.dentry, name);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long
|
||||
sys_lremovexattr(const char __user *path, const char __user *name)
|
||||
sys_lremovexattr(const char __user *pathname, const char __user *name)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_walk_link(path, &nd);
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
error = removexattr(nd.path.dentry, name);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
error = removexattr(path.dentry, name);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&nd.path);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,17 +84,15 @@ xfs_find_handle(
|
|||
switch (cmd) {
|
||||
case XFS_IOC_PATH_TO_FSHANDLE:
|
||||
case XFS_IOC_PATH_TO_HANDLE: {
|
||||
struct nameidata nd;
|
||||
int error;
|
||||
|
||||
error = user_path_walk_link((const char __user *)hreq.path, &nd);
|
||||
struct path path;
|
||||
int error = user_lpath((const char __user *)hreq.path, &path);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ASSERT(nd.path.dentry);
|
||||
ASSERT(nd.path.dentry->d_inode);
|
||||
inode = igrab(nd.path.dentry->d_inode);
|
||||
path_put(&nd.path);
|
||||
ASSERT(path.dentry);
|
||||
ASSERT(path.dentry->d_inode);
|
||||
inode = igrab(path.dentry->d_inode);
|
||||
path_put(&path);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -589,8 +589,7 @@ xfs_check_acl(
|
|||
STATIC int
|
||||
xfs_vn_permission(
|
||||
struct inode *inode,
|
||||
int mask,
|
||||
struct nameidata *nd)
|
||||
int mask)
|
||||
{
|
||||
return generic_permission(inode, mask, xfs_check_acl);
|
||||
}
|
||||
|
|
|
@ -711,7 +711,7 @@ start:
|
|||
!capable(CAP_FSETID)) {
|
||||
error = xfs_write_clear_setuid(xip);
|
||||
if (likely(!error))
|
||||
error = -remove_suid(file->f_path.dentry);
|
||||
error = -file_remove_suid(file);
|
||||
if (unlikely(error)) {
|
||||
goto out_unlock_internal;
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $
|
||||
* linux/include/asm-alpha/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __ALPHA_NAMEI_H
|
||||
#define __ALPHA_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __ALPHA_NAMEI_H */
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* linux/include/asm-arm/namei.h
|
||||
*
|
||||
* Routines to handle famous /usr/gnemul
|
||||
* Derived from the Sparc version of this file
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __ASMARM_NAMEI_H
|
||||
#define __ASMARM_NAMEI_H
|
||||
|
||||
#define ARM_BSD_EMUL "usr/gnemul/bsd/"
|
||||
|
||||
static inline char *__emul_prefix(void)
|
||||
{
|
||||
switch (current->personality) {
|
||||
case PER_BSD:
|
||||
return ARM_BSD_EMUL;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ASMARM_NAMEI_H */
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef __ASM_AVR32_NAMEI_H
|
||||
#define __ASM_AVR32_NAMEI_H
|
||||
|
||||
/* This dummy routine may be changed to something useful */
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __ASM_AVR32_NAMEI_H */
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* linux/include/asm/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*
|
||||
* Changes made by Lineo Inc. May 2001
|
||||
*/
|
||||
|
||||
#ifndef __BFIN_NAMEI_H
|
||||
#define __BFIN_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif
|
|
@ -1,17 +0,0 @@
|
|||
/* $Id: namei.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $
|
||||
* linux/include/asm-cris/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __CRIS_NAMEI_H
|
||||
#define __CRIS_NAMEI_H
|
||||
|
||||
/* used to find file-system prefixes for doing emulations
|
||||
* see for example asm-sparc/namei.h
|
||||
* we don't use it...
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __CRIS_NAMEI_H */
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* include/asm-frv/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __ASM_NAMEI_H
|
||||
#define __ASM_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* linux/include/asm-h8300/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __H8300_NAMEI_H
|
||||
#define __H8300_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef _ASM_IA64_NAMEI_H
|
||||
#define _ASM_IA64_NAMEI_H
|
||||
|
||||
/*
|
||||
* Modified 1998, 1999, 2001
|
||||
* David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
|
||||
*/
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#define EMUL_PREFIX_LINUX_IA32 "/emul/ia32-linux/"
|
||||
|
||||
static inline char *
|
||||
__emul_prefix (void)
|
||||
{
|
||||
switch (current->personality) {
|
||||
case PER_LINUX32:
|
||||
return EMUL_PREFIX_LINUX_IA32;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _ASM_IA64_NAMEI_H */
|
|
@ -1,17 +0,0 @@
|
|||
#ifndef _ASM_M32R_NAMEI_H
|
||||
#define _ASM_M32R_NAMEI_H
|
||||
|
||||
/*
|
||||
* linux/include/asm-m32r/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* _ASM_M32R_NAMEI_H */
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* linux/include/asm-m68k/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __M68K_NAMEI_H
|
||||
#define __M68K_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
#include <asm-m68k/namei.h>
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef _ASM_NAMEI_H
|
||||
#define _ASM_NAMEI_H
|
||||
|
||||
/*
|
||||
* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* _ASM_NAMEI_H */
|
|
@ -1,22 +0,0 @@
|
|||
/* Emulation stuff
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_NAMEI_H
|
||||
#define _ASM_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* _ASM_NAMEI_H */
|
|
@ -1,17 +0,0 @@
|
|||
/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $
|
||||
* linux/include/asm-parisc/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __PARISC_NAMEI_H
|
||||
#define __PARISC_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __PARISC_NAMEI_H */
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef _ASM_POWERPC_NAMEI_H
|
||||
#define _ASM_POWERPC_NAMEI_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
* Adapted from include/asm-alpha/namei.h
|
||||
*
|
||||
* Included from fs/namei.c
|
||||
*/
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _ASM_POWERPC_NAMEI_H */
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* include/asm-s390/namei.h
|
||||
*
|
||||
* S390 version
|
||||
*
|
||||
* Derived from "include/asm-i386/namei.h"
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __S390_NAMEI_H
|
||||
#define __S390_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __S390_NAMEI_H */
|
|
@ -1,17 +0,0 @@
|
|||
/* $Id: namei.h,v 1.3 2000/07/04 06:24:49 gniibe Exp $
|
||||
* linux/include/asm-sh/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __ASM_SH_NAMEI_H
|
||||
#define __ASM_SH_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __ASM_SH_NAMEI_H */
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef ___ASM_SPARC_NAMEI_H
|
||||
#define ___ASM_SPARC_NAMEI_H
|
||||
#if defined(__sparc__) && defined(__arch64__)
|
||||
#include <asm-sparc/namei_64.h>
|
||||
#else
|
||||
#include <asm-sparc/namei_32.h>
|
||||
#endif
|
||||
#endif
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* linux/include/asm-sparc/namei.h
|
||||
*
|
||||
* Routines to handle famous /usr/gnemul/s*.
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __SPARC_NAMEI_H
|
||||
#define __SPARC_NAMEI_H
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __SPARC_NAMEI_H */
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* linux/include/asm-sparc64/namei.h
|
||||
*
|
||||
* Routines to handle famous /usr/gnemul/s*.
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __SPARC64_NAMEI_H
|
||||
#define __SPARC64_NAMEI_H
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __SPARC64_NAMEI_H */
|
|
@ -1 +0,0 @@
|
|||
#include <asm-sparc/namei.h>
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef __UM_NAMEI_H
|
||||
#define __UM_NAMEI_H
|
||||
|
||||
#include "asm/arch/namei.h"
|
||||
|
||||
#endif
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* linux/include/asm-v850/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*/
|
||||
|
||||
#ifndef __V850_NAMEI_H__
|
||||
#define __V850_NAMEI_H__
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __V850_NAMEI_H__ */
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef _ASM_X86_NAMEI_H
|
||||
#define _ASM_X86_NAMEI_H
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* _ASM_X86_NAMEI_H */
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* include/asm-xtensa/namei.h
|
||||
*
|
||||
* Included from linux/fs/namei.c
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2001 - 2005 Tensilica Inc.
|
||||
*/
|
||||
|
||||
#ifndef _XTENSA_NAMEI_H
|
||||
#define _XTENSA_NAMEI_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* This dummy routine maybe changed to something useful
|
||||
* for /usr/gnemul/ emulation stuff.
|
||||
* Look at asm-sparc/namei.h for details.
|
||||
*/
|
||||
|
||||
#define __emul_prefix() NULL
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _XTENSA_NAMEI_H */
|
|
@ -37,7 +37,7 @@ extern const struct file_operations coda_ioctl_operations;
|
|||
/* operations shared over more than one file */
|
||||
int coda_open(struct inode *i, struct file *f);
|
||||
int coda_release(struct inode *i, struct file *f);
|
||||
int coda_permission(struct inode *inode, int mask, struct nameidata *nd);
|
||||
int coda_permission(struct inode *inode, int mask);
|
||||
int coda_revalidate_inode(struct dentry *);
|
||||
int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
int coda_setattr(struct dentry *, struct iattr *);
|
||||
|
|
|
@ -60,6 +60,8 @@ extern int dir_notify_enable;
|
|||
#define MAY_WRITE 2
|
||||
#define MAY_READ 4
|
||||
#define MAY_APPEND 8
|
||||
#define MAY_ACCESS 16
|
||||
#define MAY_OPEN 32
|
||||
|
||||
#define FMODE_READ 1
|
||||
#define FMODE_WRITE 2
|
||||
|
@ -277,7 +279,7 @@ extern int dir_notify_enable;
|
|||
#include <linux/types.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/path.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/cache.h>
|
||||
#include <linux/kobject.h>
|
||||
|
@ -318,22 +320,23 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
|
|||
* Attribute flags. These should be or-ed together to figure out what
|
||||
* has been changed!
|
||||
*/
|
||||
#define ATTR_MODE 1
|
||||
#define ATTR_UID 2
|
||||
#define ATTR_GID 4
|
||||
#define ATTR_SIZE 8
|
||||
#define ATTR_ATIME 16
|
||||
#define ATTR_MTIME 32
|
||||
#define ATTR_CTIME 64
|
||||
#define ATTR_ATIME_SET 128
|
||||
#define ATTR_MTIME_SET 256
|
||||
#define ATTR_FORCE 512 /* Not a change, but a change it */
|
||||
#define ATTR_ATTR_FLAG 1024
|
||||
#define ATTR_KILL_SUID 2048
|
||||
#define ATTR_KILL_SGID 4096
|
||||
#define ATTR_FILE 8192
|
||||
#define ATTR_KILL_PRIV 16384
|
||||
#define ATTR_OPEN 32768 /* Truncating from open(O_TRUNC) */
|
||||
#define ATTR_MODE (1 << 0)
|
||||
#define ATTR_UID (1 << 1)
|
||||
#define ATTR_GID (1 << 2)
|
||||
#define ATTR_SIZE (1 << 3)
|
||||
#define ATTR_ATIME (1 << 4)
|
||||
#define ATTR_MTIME (1 << 5)
|
||||
#define ATTR_CTIME (1 << 6)
|
||||
#define ATTR_ATIME_SET (1 << 7)
|
||||
#define ATTR_MTIME_SET (1 << 8)
|
||||
#define ATTR_FORCE (1 << 9) /* Not a change, but a change it */
|
||||
#define ATTR_ATTR_FLAG (1 << 10)
|
||||
#define ATTR_KILL_SUID (1 << 11)
|
||||
#define ATTR_KILL_SGID (1 << 12)
|
||||
#define ATTR_FILE (1 << 13)
|
||||
#define ATTR_KILL_PRIV (1 << 14)
|
||||
#define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */
|
||||
#define ATTR_TIMES_SET (1 << 16)
|
||||
|
||||
/*
|
||||
* This is the Inode Attributes structure, used for notify_change(). It
|
||||
|
@ -792,7 +795,7 @@ struct file {
|
|||
#define f_dentry f_path.dentry
|
||||
#define f_vfsmnt f_path.mnt
|
||||
const struct file_operations *f_op;
|
||||
atomic_t f_count;
|
||||
atomic_long_t f_count;
|
||||
unsigned int f_flags;
|
||||
mode_t f_mode;
|
||||
loff_t f_pos;
|
||||
|
@ -821,8 +824,8 @@ extern spinlock_t files_lock;
|
|||
#define file_list_lock() spin_lock(&files_lock);
|
||||
#define file_list_unlock() spin_unlock(&files_lock);
|
||||
|
||||
#define get_file(x) atomic_inc(&(x)->f_count)
|
||||
#define file_count(x) atomic_read(&(x)->f_count)
|
||||
#define get_file(x) atomic_long_inc(&(x)->f_count)
|
||||
#define file_count(x) atomic_long_read(&(x)->f_count)
|
||||
|
||||
#ifdef CONFIG_DEBUG_WRITECOUNT
|
||||
static inline void file_take_write(struct file *f)
|
||||
|
@ -1136,7 +1139,7 @@ extern int vfs_permission(struct nameidata *, int);
|
|||
extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
extern int vfs_mkdir(struct inode *, struct dentry *, int);
|
||||
extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, const char *, int);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *);
|
||||
|
@ -1272,7 +1275,7 @@ struct inode_operations {
|
|||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||
void (*truncate) (struct inode *);
|
||||
int (*permission) (struct inode *, int, struct nameidata *);
|
||||
int (*permission) (struct inode *, int);
|
||||
int (*setattr) (struct dentry *, struct iattr *);
|
||||
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
|
||||
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
|
||||
|
@ -1696,9 +1699,9 @@ extern void init_special_inode(struct inode *, umode_t, dev_t);
|
|||
extern void make_bad_inode(struct inode *);
|
||||
extern int is_bad_inode(struct inode *);
|
||||
|
||||
extern const struct file_operations read_fifo_fops;
|
||||
extern const struct file_operations write_fifo_fops;
|
||||
extern const struct file_operations rdwr_fifo_fops;
|
||||
extern const struct file_operations read_pipefifo_fops;
|
||||
extern const struct file_operations write_pipefifo_fops;
|
||||
extern const struct file_operations rdwr_pipefifo_fops;
|
||||
|
||||
extern int fs_may_remount_ro(struct super_block *);
|
||||
|
||||
|
@ -1767,7 +1770,7 @@ extern int do_remount_sb(struct super_block *sb, int flags,
|
|||
extern sector_t bmap(struct inode *, sector_t);
|
||||
#endif
|
||||
extern int notify_change(struct dentry *, struct iattr *);
|
||||
extern int permission(struct inode *, int, struct nameidata *);
|
||||
extern int inode_permission(struct inode *, int);
|
||||
extern int generic_permission(struct inode *, int,
|
||||
int (*check_acl)(struct inode *, int));
|
||||
|
||||
|
@ -1831,7 +1834,7 @@ extern void clear_inode(struct inode *);
|
|||
extern void destroy_inode(struct inode *);
|
||||
extern struct inode *new_inode(struct super_block *);
|
||||
extern int should_remove_suid(struct dentry *);
|
||||
extern int remove_suid(struct dentry *);
|
||||
extern int file_remove_suid(struct file *);
|
||||
|
||||
extern void __insert_inode_hash(struct inode *, unsigned long hashval);
|
||||
extern void remove_inode_hash(struct inode *);
|
||||
|
|
|
@ -7,7 +7,7 @@ struct fs_struct {
|
|||
atomic_t count;
|
||||
rwlock_t lock;
|
||||
int umask;
|
||||
struct path root, pwd, altroot;
|
||||
struct path root, pwd;
|
||||
};
|
||||
|
||||
#define INIT_FS { \
|
||||
|
@ -19,7 +19,6 @@ struct fs_struct {
|
|||
extern struct kmem_cache *fs_cachep;
|
||||
|
||||
extern void exit_fs(struct task_struct *);
|
||||
extern void set_fs_altroot(void);
|
||||
extern void set_fs_root(struct fs_struct *, struct path *);
|
||||
extern void set_fs_pwd(struct fs_struct *, struct path *);
|
||||
extern struct fs_struct *copy_fs_struct(struct fs_struct *);
|
||||
|
|
|
@ -47,7 +47,7 @@ struct vfsmount {
|
|||
struct list_head mnt_child; /* and going through their mnt_child */
|
||||
int mnt_flags;
|
||||
/* 4 bytes hole on 64bits arches */
|
||||
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
|
||||
const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
|
||||
struct list_head mnt_list;
|
||||
struct list_head mnt_expire; /* link in fs-specific expiry list */
|
||||
struct list_head mnt_share; /* circular list of shared mounts */
|
||||
|
|
|
@ -47,27 +47,24 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
|||
#define LOOKUP_DIRECTORY 2
|
||||
#define LOOKUP_CONTINUE 4
|
||||
#define LOOKUP_PARENT 16
|
||||
#define LOOKUP_NOALT 32
|
||||
#define LOOKUP_REVAL 64
|
||||
/*
|
||||
* Intent data
|
||||
*/
|
||||
#define LOOKUP_OPEN (0x0100)
|
||||
#define LOOKUP_CREATE (0x0200)
|
||||
#define LOOKUP_ACCESS (0x0400)
|
||||
#define LOOKUP_CHDIR (0x0800)
|
||||
|
||||
extern int __user_walk(const char __user *, unsigned, struct nameidata *);
|
||||
extern int __user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *);
|
||||
#define user_path_walk(name,nd) \
|
||||
__user_walk_fd(AT_FDCWD, name, LOOKUP_FOLLOW, nd)
|
||||
#define user_path_walk_link(name,nd) \
|
||||
__user_walk_fd(AT_FDCWD, name, 0, nd)
|
||||
extern int user_path_at(int, const char __user *, unsigned, struct path *);
|
||||
|
||||
#define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
|
||||
#define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path)
|
||||
#define user_path_dir(name, path) \
|
||||
user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path)
|
||||
|
||||
extern int path_lookup(const char *, unsigned, struct nameidata *);
|
||||
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
||||
const char *, unsigned int, struct nameidata *);
|
||||
|
||||
extern int __user_path_lookup_open(const char __user *, unsigned lookup_flags, struct nameidata *nd, int open_flags);
|
||||
extern int path_lookup_open(int dfd, const char *name, unsigned lookup_flags, struct nameidata *, int open_flags);
|
||||
extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
|
||||
int (*open)(struct inode *, struct file *));
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include <linux/in.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/rwsem.h>
|
||||
|
@ -332,7 +331,7 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
|
|||
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
|
||||
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
|
||||
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
extern int nfs_permission(struct inode *, int, struct nameidata *);
|
||||
extern int nfs_permission(struct inode *, int);
|
||||
extern int nfs_open(struct inode *, struct file *);
|
||||
extern int nfs_release(struct inode *, struct file *);
|
||||
extern int nfs_attribute_timeout(struct inode *inode);
|
||||
|
|
|
@ -282,11 +282,16 @@ union proc_op {
|
|||
struct task_struct *task);
|
||||
};
|
||||
|
||||
struct ctl_table_header;
|
||||
struct ctl_table;
|
||||
|
||||
struct proc_inode {
|
||||
struct pid *pid;
|
||||
int fd;
|
||||
union proc_op op;
|
||||
struct proc_dir_entry *pde;
|
||||
struct ctl_table_header *sysctl;
|
||||
struct ctl_table *sysctl_entry;
|
||||
struct inode vfs_inode;
|
||||
};
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче