mirror of https://github.com/torvalds/linux.git
Simplifying ->d_name audits, easy part.
Turn dentry->d_name into an anon union of const struct qsrt (d_name
itself) and a writable alias (__d_name). With constification of some
struct qstr * arguments of functions that get &dentry->d_name passed
to them, that ends up with all modifications provably done only in
fs/dcache.c (and a fairly small part of it).
Any new places doing modifications will be easy to find - grep for
__d_name will suffice.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQQqUNBr3gm4hGXdBJlZ7Krx/gZQ6wUCaNh6XAAKCRBZ7Krx/gZQ
6wIFAP9nJ9RIsTq2eiqb3YUTQsaFZNu7aqFWiHCFPeHVLzylPwEAgeoGrGdL8zNO
JqAuPPbQxN6Q6n79qAI/vfFvYQCsAQ0=
=88fF
-----END PGP SIGNATURE-----
Merge tag 'pull-qstr' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull d_name audit update from Al Viro:
"Simplifying ->d_name audits, easy part.
Turn dentry->d_name into an anon union of const struct qsrt (d_name
itself) and a writable alias (__d_name).
With constification of some struct qstr * arguments of functions that
get &dentry->d_name passed to them, that ends up with all
modifications provably done only in fs/dcache.c (and a fairly small
part of it).
Any new places doing modifications will be easy to find - grep for
__d_name will suffice"
* tag 'pull-qstr' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
make it easier to catch those who try to modify ->d_name
generic_ci_validate_strict_name(): constify name argument
afs_dir_search: constify qstr argument
afs_edit_dir_{add,remove}(): constify qstr argument
exfat_find(): constify qstr argument
security_dentry_init_security(): constify qstr argument
This commit is contained in:
commit
33fc69a05c
|
|
@ -239,7 +239,7 @@ static void afs_edit_init_block(union afs_xdr_dir_block *meta,
|
||||||
* The caller must hold the inode locked.
|
* The caller must hold the inode locked.
|
||||||
*/
|
*/
|
||||||
void afs_edit_dir_add(struct afs_vnode *vnode,
|
void afs_edit_dir_add(struct afs_vnode *vnode,
|
||||||
struct qstr *name, struct afs_fid *new_fid,
|
const struct qstr *name, struct afs_fid *new_fid,
|
||||||
enum afs_edit_dir_reason why)
|
enum afs_edit_dir_reason why)
|
||||||
{
|
{
|
||||||
union afs_xdr_dir_block *meta, *block;
|
union afs_xdr_dir_block *meta, *block;
|
||||||
|
|
@ -391,7 +391,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
|
||||||
* The caller must hold the inode locked.
|
* The caller must hold the inode locked.
|
||||||
*/
|
*/
|
||||||
void afs_edit_dir_remove(struct afs_vnode *vnode,
|
void afs_edit_dir_remove(struct afs_vnode *vnode,
|
||||||
struct qstr *name, enum afs_edit_dir_reason why)
|
const struct qstr *name, enum afs_edit_dir_reason why)
|
||||||
{
|
{
|
||||||
union afs_xdr_dir_block *meta, *block, *pblock;
|
union afs_xdr_dir_block *meta, *block, *pblock;
|
||||||
union afs_xdr_dirent *de, *pde;
|
union afs_xdr_dirent *de, *pde;
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ int afs_dir_search_bucket(struct afs_dir_iter *iter, const struct qstr *name,
|
||||||
/*
|
/*
|
||||||
* Search the appropriate hash chain in the contents of an AFS directory.
|
* Search the appropriate hash chain in the contents of an AFS directory.
|
||||||
*/
|
*/
|
||||||
int afs_dir_search(struct afs_vnode *dvnode, struct qstr *name,
|
int afs_dir_search(struct afs_vnode *dvnode, const struct qstr *name,
|
||||||
struct afs_fid *_fid, afs_dataversion_t *_dir_version)
|
struct afs_fid *_fid, afs_dataversion_t *_dir_version)
|
||||||
{
|
{
|
||||||
struct afs_dir_iter iter = { .dvnode = dvnode, };
|
struct afs_dir_iter iter = { .dvnode = dvnode, };
|
||||||
|
|
|
||||||
|
|
@ -1099,9 +1099,9 @@ int afs_single_writepages(struct address_space *mapping,
|
||||||
/*
|
/*
|
||||||
* dir_edit.c
|
* dir_edit.c
|
||||||
*/
|
*/
|
||||||
extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *,
|
extern void afs_edit_dir_add(struct afs_vnode *, const struct qstr *, struct afs_fid *,
|
||||||
enum afs_edit_dir_reason);
|
enum afs_edit_dir_reason);
|
||||||
extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason);
|
extern void afs_edit_dir_remove(struct afs_vnode *, const struct qstr *, enum afs_edit_dir_reason);
|
||||||
void afs_edit_dir_update(struct afs_vnode *vnode, const struct qstr *name,
|
void afs_edit_dir_update(struct afs_vnode *vnode, const struct qstr *name,
|
||||||
struct afs_vnode *new_dvnode, enum afs_edit_dir_reason why);
|
struct afs_vnode *new_dvnode, enum afs_edit_dir_reason why);
|
||||||
void afs_mkdir_init_dir(struct afs_vnode *dvnode, struct afs_vnode *parent_vnode);
|
void afs_mkdir_init_dir(struct afs_vnode *dvnode, struct afs_vnode *parent_vnode);
|
||||||
|
|
@ -1114,7 +1114,7 @@ bool afs_dir_init_iter(struct afs_dir_iter *iter, const struct qstr *name);
|
||||||
union afs_xdr_dir_block *afs_dir_find_block(struct afs_dir_iter *iter, size_t block);
|
union afs_xdr_dir_block *afs_dir_find_block(struct afs_dir_iter *iter, size_t block);
|
||||||
int afs_dir_search_bucket(struct afs_dir_iter *iter, const struct qstr *name,
|
int afs_dir_search_bucket(struct afs_dir_iter *iter, const struct qstr *name,
|
||||||
struct afs_fid *_fid);
|
struct afs_fid *_fid);
|
||||||
int afs_dir_search(struct afs_vnode *dvnode, struct qstr *name,
|
int afs_dir_search(struct afs_vnode *dvnode, const struct qstr *name,
|
||||||
struct afs_fid *_fid, afs_dataversion_t *_dir_version);
|
struct afs_fid *_fid, afs_dataversion_t *_dir_version);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
26
fs/dcache.c
26
fs/dcache.c
|
|
@ -1717,13 +1717,13 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
||||||
dname = dentry->d_shortname.string;
|
dname = dentry->d_shortname.string;
|
||||||
}
|
}
|
||||||
|
|
||||||
dentry->d_name.len = name->len;
|
dentry->__d_name.len = name->len;
|
||||||
dentry->d_name.hash = name->hash;
|
dentry->__d_name.hash = name->hash;
|
||||||
memcpy(dname, name->name, name->len);
|
memcpy(dname, name->name, name->len);
|
||||||
dname[name->len] = 0;
|
dname[name->len] = 0;
|
||||||
|
|
||||||
/* Make sure we always see the terminating NUL character */
|
/* Make sure we always see the terminating NUL character */
|
||||||
smp_store_release(&dentry->d_name.name, dname); /* ^^^ */
|
smp_store_release(&dentry->__d_name.name, dname); /* ^^^ */
|
||||||
|
|
||||||
dentry->d_flags = 0;
|
dentry->d_flags = 0;
|
||||||
lockref_init(&dentry->d_lockref);
|
lockref_init(&dentry->d_lockref);
|
||||||
|
|
@ -2743,15 +2743,15 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
|
||||||
/*
|
/*
|
||||||
* Both external: swap the pointers
|
* Both external: swap the pointers
|
||||||
*/
|
*/
|
||||||
swap(target->d_name.name, dentry->d_name.name);
|
swap(target->__d_name.name, dentry->__d_name.name);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* dentry:internal, target:external. Steal target's
|
* dentry:internal, target:external. Steal target's
|
||||||
* storage and make target internal.
|
* storage and make target internal.
|
||||||
*/
|
*/
|
||||||
dentry->d_name.name = target->d_name.name;
|
dentry->__d_name.name = target->__d_name.name;
|
||||||
target->d_shortname = dentry->d_shortname;
|
target->d_shortname = dentry->d_shortname;
|
||||||
target->d_name.name = target->d_shortname.string;
|
target->__d_name.name = target->d_shortname.string;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (unlikely(dname_external(dentry))) {
|
if (unlikely(dname_external(dentry))) {
|
||||||
|
|
@ -2759,9 +2759,9 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
|
||||||
* dentry:external, target:internal. Give dentry's
|
* dentry:external, target:internal. Give dentry's
|
||||||
* storage to target and make dentry internal
|
* storage to target and make dentry internal
|
||||||
*/
|
*/
|
||||||
target->d_name.name = dentry->d_name.name;
|
target->__d_name.name = dentry->__d_name.name;
|
||||||
dentry->d_shortname = target->d_shortname;
|
dentry->d_shortname = target->d_shortname;
|
||||||
dentry->d_name.name = dentry->d_shortname.string;
|
dentry->__d_name.name = dentry->d_shortname.string;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Both are internal.
|
* Both are internal.
|
||||||
|
|
@ -2771,7 +2771,7 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
|
||||||
target->d_shortname.words[i]);
|
target->d_shortname.words[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
swap(dentry->d_name.hash_len, target->d_name.hash_len);
|
swap(dentry->__d_name.hash_len, target->__d_name.hash_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_name(struct dentry *dentry, struct dentry *target)
|
static void copy_name(struct dentry *dentry, struct dentry *target)
|
||||||
|
|
@ -2781,11 +2781,11 @@ static void copy_name(struct dentry *dentry, struct dentry *target)
|
||||||
old_name = external_name(dentry);
|
old_name = external_name(dentry);
|
||||||
if (unlikely(dname_external(target))) {
|
if (unlikely(dname_external(target))) {
|
||||||
atomic_inc(&external_name(target)->count);
|
atomic_inc(&external_name(target)->count);
|
||||||
dentry->d_name = target->d_name;
|
dentry->__d_name = target->__d_name;
|
||||||
} else {
|
} else {
|
||||||
dentry->d_shortname = target->d_shortname;
|
dentry->d_shortname = target->d_shortname;
|
||||||
dentry->d_name.name = dentry->d_shortname.string;
|
dentry->__d_name.name = dentry->d_shortname.string;
|
||||||
dentry->d_name.hash_len = target->d_name.hash_len;
|
dentry->__d_name.hash_len = target->__d_name.hash_len;
|
||||||
}
|
}
|
||||||
if (old_name && likely(atomic_dec_and_test(&old_name->count)))
|
if (old_name && likely(atomic_dec_and_test(&old_name->count)))
|
||||||
kfree_rcu(old_name, head);
|
kfree_rcu(old_name, head);
|
||||||
|
|
@ -3134,7 +3134,7 @@ void d_mark_tmpfile(struct file *file, struct inode *inode)
|
||||||
!d_unlinked(dentry));
|
!d_unlinked(dentry));
|
||||||
spin_lock(&dentry->d_parent->d_lock);
|
spin_lock(&dentry->d_parent->d_lock);
|
||||||
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
dentry->d_name.len = sprintf(dentry->d_shortname.string, "#%llu",
|
dentry->__d_name.len = sprintf(dentry->d_shortname.string, "#%llu",
|
||||||
(unsigned long long)inode->i_ino);
|
(unsigned long long)inode->i_ino);
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&dentry->d_parent->d_lock);
|
spin_unlock(&dentry->d_parent->d_lock);
|
||||||
|
|
|
||||||
|
|
@ -587,7 +587,7 @@ static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lookup a file */
|
/* lookup a file */
|
||||||
static int exfat_find(struct inode *dir, struct qstr *qname,
|
static int exfat_find(struct inode *dir, const struct qstr *qname,
|
||||||
struct exfat_dir_entry *info)
|
struct exfat_dir_entry *info)
|
||||||
{
|
{
|
||||||
int ret, dentry, count;
|
int ret, dentry, count;
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,10 @@ struct dentry {
|
||||||
seqcount_spinlock_t d_seq; /* per dentry seqlock */
|
seqcount_spinlock_t d_seq; /* per dentry seqlock */
|
||||||
struct hlist_bl_node d_hash; /* lookup hash list */
|
struct hlist_bl_node d_hash; /* lookup hash list */
|
||||||
struct dentry *d_parent; /* parent directory */
|
struct dentry *d_parent; /* parent directory */
|
||||||
struct qstr d_name;
|
union {
|
||||||
|
struct qstr __d_name; /* for use ONLY in fs/dcache.c */
|
||||||
|
const struct qstr d_name;
|
||||||
|
};
|
||||||
struct inode *d_inode; /* Where the name belongs to - NULL is
|
struct inode *d_inode; /* Where the name belongs to - NULL is
|
||||||
* negative */
|
* negative */
|
||||||
union shortname_store d_shortname;
|
union shortname_store d_shortname;
|
||||||
|
|
|
||||||
|
|
@ -3716,7 +3716,8 @@ int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
|
||||||
* happens when a directory is casefolded and the filesystem is strict
|
* happens when a directory is casefolded and the filesystem is strict
|
||||||
* about its encoding.
|
* about its encoding.
|
||||||
*/
|
*/
|
||||||
static inline bool generic_ci_validate_strict_name(struct inode *dir, struct qstr *name)
|
static inline bool generic_ci_validate_strict_name(struct inode *dir,
|
||||||
|
const struct qstr *name)
|
||||||
{
|
{
|
||||||
if (!IS_CASEFOLDED(dir) || !sb_has_strict_encoding(dir->i_sb))
|
if (!IS_CASEFOLDED(dir) || !sb_has_strict_encoding(dir->i_sb))
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -3731,7 +3732,8 @@ static inline bool generic_ci_validate_strict_name(struct inode *dir, struct qst
|
||||||
return !utf8_validate(dir->i_sb->s_encoding, name);
|
return !utf8_validate(dir->i_sb->s_encoding, name);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline bool generic_ci_validate_strict_name(struct inode *dir, struct qstr *name)
|
static inline bool generic_ci_validate_strict_name(struct inode *dir,
|
||||||
|
const struct qstr *name)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ LSM_HOOK(int, -EOPNOTSUPP, dentry_init_security, struct dentry *dentry,
|
||||||
int mode, const struct qstr *name, const char **xattr_name,
|
int mode, const struct qstr *name, const char **xattr_name,
|
||||||
struct lsm_context *cp)
|
struct lsm_context *cp)
|
||||||
LSM_HOOK(int, 0, dentry_create_files_as, struct dentry *dentry, int mode,
|
LSM_HOOK(int, 0, dentry_create_files_as, struct dentry *dentry, int mode,
|
||||||
struct qstr *name, const struct cred *old, struct cred *new)
|
const struct qstr *name, const struct cred *old, struct cred *new)
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_PATH
|
#ifdef CONFIG_SECURITY_PATH
|
||||||
LSM_HOOK(int, 0, path_unlink, const struct path *dir, struct dentry *dentry)
|
LSM_HOOK(int, 0, path_unlink, const struct path *dir, struct dentry *dentry)
|
||||||
|
|
|
||||||
|
|
@ -391,7 +391,7 @@ int security_dentry_init_security(struct dentry *dentry, int mode,
|
||||||
const char **xattr_name,
|
const char **xattr_name,
|
||||||
struct lsm_context *lsmcxt);
|
struct lsm_context *lsmcxt);
|
||||||
int security_dentry_create_files_as(struct dentry *dentry, int mode,
|
int security_dentry_create_files_as(struct dentry *dentry, int mode,
|
||||||
struct qstr *name,
|
const struct qstr *name,
|
||||||
const struct cred *old,
|
const struct cred *old,
|
||||||
struct cred *new);
|
struct cred *new);
|
||||||
int security_path_notify(const struct path *path, u64 mask,
|
int security_path_notify(const struct path *path, u64 mask,
|
||||||
|
|
@ -872,7 +872,7 @@ static inline int security_dentry_init_security(struct dentry *dentry,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int security_dentry_create_files_as(struct dentry *dentry,
|
static inline int security_dentry_create_files_as(struct dentry *dentry,
|
||||||
int mode, struct qstr *name,
|
int mode, const struct qstr *name,
|
||||||
const struct cred *old,
|
const struct cred *old,
|
||||||
struct cred *new)
|
struct cred *new)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1814,7 +1814,7 @@ EXPORT_SYMBOL(security_dentry_init_security);
|
||||||
* Return: Returns 0 on success, error on failure.
|
* Return: Returns 0 on success, error on failure.
|
||||||
*/
|
*/
|
||||||
int security_dentry_create_files_as(struct dentry *dentry, int mode,
|
int security_dentry_create_files_as(struct dentry *dentry, int mode,
|
||||||
struct qstr *name,
|
const struct qstr *name,
|
||||||
const struct cred *old, struct cred *new)
|
const struct cred *old, struct cred *new)
|
||||||
{
|
{
|
||||||
return call_int_hook(dentry_create_files_as, dentry, mode,
|
return call_int_hook(dentry_create_files_as, dentry, mode,
|
||||||
|
|
|
||||||
|
|
@ -2905,7 +2905,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
|
static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
|
||||||
struct qstr *name,
|
const struct qstr *name,
|
||||||
const struct cred *old,
|
const struct cred *old,
|
||||||
struct cred *new)
|
struct cred *new)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4908,7 +4908,7 @@ static int smack_inode_copy_up_xattr(struct dentry *src, const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
|
static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
|
||||||
struct qstr *name,
|
const struct qstr *name,
|
||||||
const struct cred *old,
|
const struct cred *old,
|
||||||
struct cred *new)
|
struct cred *new)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue