mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 16:35:02 +01:00
362 lines
12 KiB
Diff
362 lines
12 KiB
Diff
Index: b/security/apparmor/lsm.c
|
|
===================================================================
|
|
--- a/security/apparmor/lsm.c
|
|
+++ b/security/apparmor/lsm.c
|
|
@@ -251,7 +251,7 @@ out:
|
|
}
|
|
|
|
static int aa_permission(struct inode *inode, struct dentry *dentry,
|
|
- struct vfsmount *mnt, int mask, int leaf)
|
|
+ struct vfsmount *mnt, int mask, int check)
|
|
{
|
|
int error = 0;
|
|
|
|
@@ -259,7 +259,7 @@ static int aa_permission(struct inode *i
|
|
struct aa_profile *profile = aa_get_profile(current);
|
|
|
|
if (profile)
|
|
- error = aa_perm(profile, dentry, mnt, mask, leaf);
|
|
+ error = aa_perm(profile, dentry, mnt, mask, check);
|
|
aa_put_profile(profile);
|
|
}
|
|
return error;
|
|
@@ -268,7 +268,7 @@ static int aa_permission(struct inode *i
|
|
static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
|
|
struct vfsmount *mnt, int mask)
|
|
{
|
|
- return aa_permission(dir, dentry, mnt, MAY_WRITE, 1);
|
|
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, AA_CHECK_LEAF);
|
|
}
|
|
|
|
static int apparmor_inode_link(struct dentry *old_dentry,
|
|
@@ -298,19 +298,19 @@ static int apparmor_inode_unlink(struct
|
|
struct dentry *dentry,
|
|
struct vfsmount *mnt)
|
|
{
|
|
- return aa_permission(dir, dentry, mnt, MAY_WRITE, 1);
|
|
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, AA_CHECK_LEAF);
|
|
}
|
|
|
|
static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry,
|
|
struct vfsmount *mnt, const char *old_name)
|
|
{
|
|
- return aa_permission(dir, dentry, mnt, MAY_WRITE, 1);
|
|
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, AA_CHECK_LEAF);
|
|
}
|
|
|
|
static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
|
|
struct vfsmount *mnt, int mode, dev_t dev)
|
|
{
|
|
- return aa_permission(dir, dentry, mnt, MAY_WRITE, 1);
|
|
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, AA_CHECK_LEAF);
|
|
}
|
|
|
|
static int apparmor_inode_rename(struct inode *old_dir,
|
|
@@ -331,11 +331,11 @@ static int apparmor_inode_rename(struct
|
|
if (profile) {
|
|
if (old_mnt)
|
|
error = aa_perm(profile, old_dentry, old_mnt,
|
|
- MAY_READ | MAY_WRITE, 1);
|
|
+ MAY_READ | MAY_WRITE, AA_CHECK_LEAF);
|
|
|
|
if (!error && new_mnt)
|
|
error = aa_perm(profile, new_dentry, new_mnt,
|
|
- MAY_WRITE, 1);
|
|
+ MAY_WRITE, AA_CHECK_LEAF);
|
|
}
|
|
|
|
aa_put_profile(profile);
|
|
@@ -395,16 +395,17 @@ out:
|
|
|
|
static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
|
|
const char *name, const char *operation,
|
|
- int mask)
|
|
+ int mask, struct file *file)
|
|
{
|
|
int error = 0;
|
|
|
|
if (mnt && mediated_filesystem(dentry->d_inode)) {
|
|
struct aa_profile *profile = aa_get_profile(current);
|
|
+ int check = file ? AA_CHECK_FD : 0;
|
|
|
|
if (profile)
|
|
error = aa_perm_xattr(profile, dentry, mnt, name,
|
|
- operation, mask);
|
|
+ operation, mask, check);
|
|
aa_put_profile(profile);
|
|
}
|
|
|
|
@@ -413,27 +414,32 @@ static int aa_xattr_permission(struct de
|
|
|
|
static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
|
char *name, void *value, size_t size,
|
|
- int flags)
|
|
+ int flags, struct file *file)
|
|
{
|
|
- return aa_xattr_permission(dentry, mnt, name, "xattr set", MAY_WRITE);
|
|
+ return aa_xattr_permission(dentry, mnt, name, "xattr set", MAY_WRITE,
|
|
+ file);
|
|
}
|
|
|
|
static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
|
- char *name)
|
|
+ char *name, struct file *file)
|
|
{
|
|
- return aa_xattr_permission(dentry, mnt, name, "xattr get", MAY_READ);
|
|
+ return aa_xattr_permission(dentry, mnt, name, "xattr get", MAY_READ,
|
|
+ file);
|
|
}
|
|
|
|
-static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
|
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
|
+ struct file *file)
|
|
{
|
|
- return aa_xattr_permission(dentry, mnt, NULL, "xattr list", MAY_READ);
|
|
+ return aa_xattr_permission(dentry, mnt, NULL, "xattr list", MAY_READ,
|
|
+ file);
|
|
}
|
|
|
|
static int apparmor_inode_removexattr(struct dentry *dentry,
|
|
- struct vfsmount *mnt, char *name)
|
|
+ struct vfsmount *mnt, char *name,
|
|
+ struct file *file)
|
|
{
|
|
return aa_xattr_permission(dentry, mnt, name, "xattr remove",
|
|
- MAY_WRITE);
|
|
+ MAY_WRITE, file);
|
|
}
|
|
|
|
static int apparmor_file_permission(struct file *file, int mask)
|
|
@@ -459,7 +465,8 @@ static int apparmor_file_permission(stru
|
|
* against.
|
|
*/
|
|
mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
|
|
- error = aa_permission(dentry->d_inode, dentry, mnt, mask, 1);
|
|
+ error = aa_permission(dentry->d_inode, dentry, mnt, mask,
|
|
+ AA_CHECK_LEAF | AA_CHECK_FD);
|
|
}
|
|
aa_put_profile(profile);
|
|
|
|
@@ -520,7 +527,8 @@ static inline int aa_mmap(struct file *f
|
|
mask |= AA_EXEC_MMAP;
|
|
|
|
dentry = file->f_dentry;
|
|
- return aa_permission(dentry->d_inode, dentry, file->f_vfsmnt, mask, 1);
|
|
+ return aa_permission(dentry->d_inode, dentry, file->f_vfsmnt, mask,
|
|
+ AA_CHECK_LEAF | AA_CHECK_FD);
|
|
}
|
|
|
|
static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
|
|
Index: b/security/apparmor/main.c
|
|
===================================================================
|
|
--- a/security/apparmor/main.c
|
|
+++ b/security/apparmor/main.c
|
|
@@ -137,13 +137,12 @@ static int aa_link_denied(struct aa_prof
|
|
}
|
|
|
|
static char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt,
|
|
- char **buffer, int is_dir)
|
|
+ char **buffer, int check)
|
|
{
|
|
char *name;
|
|
- int size = 256;
|
|
+ int is_dir, size = 256;
|
|
|
|
- /* Make sure is_dir is either 0 or 1. */
|
|
- is_dir = !!is_dir;
|
|
+ is_dir = (check & AA_CHECK_DIR) ? 1 : 0;
|
|
|
|
for (;;) {
|
|
char *buf = kmalloc(size, GFP_KERNEL);
|
|
@@ -190,19 +189,19 @@ static inline void aa_put_name_buffer(ch
|
|
|
|
static int aa_perm_dentry(struct aa_profile *profile, struct dentry *dentry,
|
|
struct vfsmount *mnt, struct aa_audit *sa, int mask,
|
|
- int is_dir, int accessed_through_fd)
|
|
+ int check)
|
|
{
|
|
char *buffer = NULL;
|
|
int denied_mask, error;
|
|
|
|
- sa->name = aa_get_name(dentry, mnt, &buffer, is_dir);
|
|
+ sa->name = aa_get_name(dentry, mnt, &buffer, check);
|
|
|
|
if (IS_ERR(sa->name)) {
|
|
/*
|
|
* deleted files are given a pass on permission checks when
|
|
* accessed through a file descriptor.
|
|
*/
|
|
- if (PTR_ERR(sa->name) == -ENOENT && accessed_through_fd)
|
|
+ if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
|
|
denied_mask = 0;
|
|
else
|
|
denied_mask = PTR_ERR(sa->name);
|
|
@@ -532,7 +531,8 @@ out:
|
|
int aa_attr(struct aa_profile *profile, struct dentry *dentry,
|
|
struct vfsmount *mnt, struct iattr *iattr)
|
|
{
|
|
- int error;
|
|
+ struct inode *inode = dentry->d_inode;
|
|
+ int error, check;
|
|
struct aa_audit sa;
|
|
|
|
sa.type = AA_AUDITTYPE_ATTR;
|
|
@@ -540,9 +540,13 @@ int aa_attr(struct aa_profile *profile,
|
|
sa.flags = 0;
|
|
sa.gfp_mask = GFP_KERNEL;
|
|
|
|
- error = aa_perm_dentry(profile, dentry, mnt, &sa, MAY_WRITE,
|
|
- S_ISDIR(dentry->d_inode->i_mode),
|
|
- iattr->ia_valid & ATTR_FILE);
|
|
+ check = 0;
|
|
+ if (inode && S_ISDIR(inode->i_mode))
|
|
+ check |= AA_CHECK_DIR;
|
|
+ if (iattr->ia_valid & ATTR_FILE)
|
|
+ check |= AA_CHECK_FD;
|
|
+
|
|
+ error = aa_perm_dentry(profile, dentry, mnt, &sa, MAY_WRITE, check);
|
|
|
|
return error;
|
|
}
|
|
@@ -558,8 +562,9 @@ int aa_attr(struct aa_profile *profile,
|
|
*/
|
|
int aa_perm_xattr(struct aa_profile *profile, struct dentry *dentry,
|
|
struct vfsmount *mnt, const char *operation,
|
|
- const char *xattr_name, int mask)
|
|
+ const char *xattr_name, int mask, int check)
|
|
{
|
|
+ struct inode *inode = dentry->d_inode;
|
|
int error;
|
|
struct aa_audit sa;
|
|
|
|
@@ -569,9 +574,10 @@ int aa_perm_xattr(struct aa_profile *pro
|
|
sa.flags = 0;
|
|
sa.gfp_mask = GFP_KERNEL;
|
|
|
|
- error = aa_perm_dentry(profile, dentry, mnt, &sa, mask,
|
|
- S_ISDIR(dentry->d_inode->i_mode),
|
|
- 0 /* FIXME */);
|
|
+ if (inode && S_ISDIR(inode->i_mode))
|
|
+ check |= AA_CHECK_DIR;
|
|
+
|
|
+ error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check);
|
|
|
|
return error;
|
|
}
|
|
@@ -588,13 +594,16 @@ int aa_perm_xattr(struct aa_profile *pro
|
|
* profile. Result, %0 (success), -ve (error)
|
|
*/
|
|
int aa_perm(struct aa_profile *profile, struct dentry *dentry,
|
|
- struct vfsmount *mnt, int mask, int leaf)
|
|
+ struct vfsmount *mnt, int mask, int check)
|
|
{
|
|
struct inode *inode = dentry->d_inode;
|
|
struct aa_audit sa;
|
|
int error = 0;
|
|
|
|
- if (!leaf && inode && S_ISDIR(inode->i_mode)) {
|
|
+ if (inode && S_ISDIR(inode->i_mode))
|
|
+ check |= AA_CHECK_DIR;
|
|
+
|
|
+ if ((check & (AA_CHECK_DIR | AA_CHECK_LEAF)) == AA_CHECK_DIR) {
|
|
/*
|
|
* If checking a non-leaf directory, allow traverse and
|
|
* write access: we do not require profile access to
|
|
@@ -612,9 +621,7 @@ int aa_perm(struct aa_profile *profile,
|
|
sa.mask = mask;
|
|
sa.flags = 0;
|
|
sa.gfp_mask = GFP_KERNEL;
|
|
- error = aa_perm_dentry(profile, dentry, mnt, &sa, mask,
|
|
- inode && S_ISDIR(inode->i_mode),
|
|
- 0 /* FIXME */);
|
|
+ error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check);
|
|
|
|
out:
|
|
return error;
|
|
@@ -642,8 +649,7 @@ int aa_perm_dir(struct aa_profile *profi
|
|
sa.flags = 0;
|
|
sa.gfp_mask = GFP_KERNEL;
|
|
|
|
- return aa_perm_dentry(profile, dentry, mnt, &sa, mask, 1,
|
|
- 0 /* FIXME */);
|
|
+ return aa_perm_dentry(profile, dentry, mnt, &sa, mask, AA_CHECK_DIR);
|
|
}
|
|
|
|
/**
|
|
Index: b/security/apparmor/apparmor.h
|
|
===================================================================
|
|
--- a/security/apparmor/apparmor.h
|
|
+++ b/security/apparmor/apparmor.h
|
|
@@ -204,6 +204,11 @@ struct aa_audit {
|
|
"LOGPROF-HINT " hint " " fmt, ##args);\
|
|
} while(0)
|
|
|
|
+/* Flags for the permission check functions */
|
|
+#define AA_CHECK_LEAF 1 /* this is the leaf lookup component */
|
|
+#define AA_CHECK_FD 2 /* coming from a file descriptor */
|
|
+#define AA_CHECK_DIR 4 /* file type is directory */
|
|
+
|
|
/* main.c */
|
|
extern int alloc_null_complain_profile(void);
|
|
extern void free_null_complain_profile(void);
|
|
@@ -218,10 +223,10 @@ extern int aa_attr(struct aa_profile *pr
|
|
struct vfsmount *mnt, struct iattr *iattr);
|
|
extern int aa_perm_xattr(struct aa_profile *profile, struct dentry *dentry,
|
|
struct vfsmount *mnt, const char *operation,
|
|
- const char *xattr_xattr, int mask);
|
|
+ const char *xattr_xattr, int mask, int check);
|
|
extern int aa_capability(struct aa_profile *profile, int cap);
|
|
extern int aa_perm(struct aa_profile *profile, struct dentry *dentry,
|
|
- struct vfsmount *mnt, int mask, int leaf);
|
|
+ struct vfsmount *mnt, int mask, int check);
|
|
extern int aa_perm_dir(struct aa_profile *profile, struct dentry *dentry,
|
|
struct vfsmount *mnt, const char *operation, int mask);
|
|
extern int aa_link(struct aa_profile *profile,
|
|
Index: b/fs/nfsd/vfs.c
|
|
===================================================================
|
|
--- a/fs/nfsd/vfs.c
|
|
+++ b/fs/nfsd/vfs.c
|
|
@@ -383,7 +383,7 @@ static ssize_t nfsd_getxattr(struct dent
|
|
{
|
|
ssize_t buflen;
|
|
|
|
- buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
|
|
+ buflen = vfs_getxattr(dentry, mnt, key, NULL, 0, NULL);
|
|
if (buflen <= 0)
|
|
return buflen;
|
|
|
|
@@ -391,7 +391,7 @@ static ssize_t nfsd_getxattr(struct dent
|
|
if (!*buf)
|
|
return -ENOMEM;
|
|
|
|
- return vfs_getxattr(dentry, mnt, key, *buf, buflen);
|
|
+ return vfs_getxattr(dentry, mnt, key, *buf, buflen, NULL);
|
|
}
|
|
#endif
|
|
|
|
@@ -417,7 +417,7 @@ set_nfsv4_acl_one(struct dentry *dentry,
|
|
goto out;
|
|
}
|
|
|
|
- error = vfs_setxattr(dentry, mnt, key, buf, len, 0);
|
|
+ error = vfs_setxattr(dentry, mnt, key, buf, len, 0, NULL);
|
|
out:
|
|
kfree(buf);
|
|
return error;
|
|
@@ -1984,13 +1984,14 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
|
|
|
|
if (size)
|
|
error = vfs_setxattr(fhp->fh_dentry, fhp->fh_export->ex_mnt,
|
|
- name, value, size,0);
|
|
+ name, value, size, 0, NULL);
|
|
else {
|
|
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
|
|
error = 0;
|
|
else {
|
|
error = vfs_removexattr(fhp->fh_dentry,
|
|
- fhp->fh_export->ex_mnt, name);
|
|
+ fhp->fh_export->ex_mnt, name,
|
|
+ NULL);
|
|
if (error == -ENODATA)
|
|
error = 0;
|
|
}
|