Merge "Merge 8ad78685ff ("Merge tag 'pstore-v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux") into android-mainline" into android-mainline
This commit is contained in:
+1
-1
@@ -14734,7 +14734,7 @@ NETWORKING [LABELED] (NetLabel, Labeled IPsec, SECMARK)
|
||||
M: Paul Moore <paul@paul-moore.com>
|
||||
L: netdev@vger.kernel.org
|
||||
L: linux-security-module@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Supported
|
||||
W: https://github.com/netlabel
|
||||
F: Documentation/netlabel/
|
||||
F: include/net/calipso.h
|
||||
|
||||
@@ -1214,13 +1214,6 @@ config COMPAT_32BIT_TIME
|
||||
config ARCH_NO_PREEMPT
|
||||
bool
|
||||
|
||||
config ARCH_EPHEMERAL_INODES
|
||||
def_bool n
|
||||
help
|
||||
An arch should select this symbol if it doesn't keep track of inode
|
||||
instances on its own, but instead relies on something else (e.g. the
|
||||
host kernel for an UML kernel).
|
||||
|
||||
config ARCH_SUPPORTS_RT
|
||||
bool
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ menu "UML-specific options"
|
||||
config UML
|
||||
bool
|
||||
default y
|
||||
select ARCH_EPHEMERAL_INODES
|
||||
select ARCH_HAS_CPU_FINALIZE_INIT
|
||||
select ARCH_HAS_FORTIFY_SOURCE
|
||||
select ARCH_HAS_GCOV_PROFILE_ALL
|
||||
|
||||
+2
-2
@@ -1517,7 +1517,7 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset)
|
||||
phdr->p_filesz = sz;
|
||||
phdr->p_memsz = 0;
|
||||
phdr->p_flags = 0;
|
||||
phdr->p_align = 0;
|
||||
phdr->p_align = 4;
|
||||
}
|
||||
|
||||
static void fill_note(struct memelfnote *note, const char *name, int type,
|
||||
@@ -1773,7 +1773,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
|
||||
/*
|
||||
* NT_PRSTATUS is the one special case, because the regset data
|
||||
* goes into the pr_reg field inside the note contents, rather
|
||||
* than being the whole note contents. We fill the reset in here.
|
||||
* than being the whole note contents. We fill the regset in here.
|
||||
* We assume that regset 0 is NT_PRSTATUS.
|
||||
*/
|
||||
fill_prstatus(&t->prstatus.common, t->task, signr);
|
||||
|
||||
@@ -743,12 +743,12 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
|
||||
struct elf32_fdpic_loadmap *loadmap;
|
||||
#ifdef CONFIG_MMU
|
||||
struct elf32_fdpic_loadseg *mseg;
|
||||
unsigned long load_addr;
|
||||
#endif
|
||||
struct elf32_fdpic_loadseg *seg;
|
||||
struct elf32_phdr *phdr;
|
||||
unsigned long load_addr, stop;
|
||||
unsigned nloads, tmp;
|
||||
size_t size;
|
||||
unsigned long stop;
|
||||
int loop, ret;
|
||||
|
||||
/* allocate a load map table */
|
||||
@@ -760,8 +760,7 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
|
||||
if (nloads == 0)
|
||||
return -ELIBBAD;
|
||||
|
||||
size = sizeof(*loadmap) + nloads * sizeof(*seg);
|
||||
loadmap = kzalloc(size, GFP_KERNEL);
|
||||
loadmap = kzalloc(struct_size(loadmap, segs, nloads), GFP_KERNEL);
|
||||
if (!loadmap)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -770,9 +769,6 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
|
||||
loadmap->version = ELF32_FDPIC_LOADMAP_VERSION;
|
||||
loadmap->nsegs = nloads;
|
||||
|
||||
load_addr = params->load_addr;
|
||||
seg = loadmap->segs;
|
||||
|
||||
/* map the requested LOADs into the memory space */
|
||||
switch (params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) {
|
||||
case ELF_FDPIC_FLAG_CONSTDISP:
|
||||
@@ -1269,7 +1265,7 @@ static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offs
|
||||
phdr->p_filesz = sz;
|
||||
phdr->p_memsz = 0;
|
||||
phdr->p_flags = 0;
|
||||
phdr->p_align = 0;
|
||||
phdr->p_align = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ struct hostfs_stat {
|
||||
unsigned long long blocks;
|
||||
unsigned int maj;
|
||||
unsigned int min;
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
extern int stat_file(const char *path, struct hostfs_stat *p, int fd);
|
||||
|
||||
+106
-107
@@ -26,6 +26,7 @@ struct hostfs_inode_info {
|
||||
fmode_t mode;
|
||||
struct inode vfs_inode;
|
||||
struct mutex open_mutex;
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
|
||||
@@ -182,14 +183,6 @@ static char *follow_link(char *link)
|
||||
return ERR_PTR(n);
|
||||
}
|
||||
|
||||
static struct inode *hostfs_iget(struct super_block *sb)
|
||||
{
|
||||
struct inode *inode = new_inode(sb);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return inode;
|
||||
}
|
||||
|
||||
static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
|
||||
{
|
||||
/*
|
||||
@@ -228,6 +221,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
|
||||
return NULL;
|
||||
hi->fd = -1;
|
||||
hi->mode = 0;
|
||||
hi->dev = 0;
|
||||
inode_init_once(&hi->vfs_inode);
|
||||
mutex_init(&hi->open_mutex);
|
||||
return &hi->vfs_inode;
|
||||
@@ -240,6 +234,7 @@ static void hostfs_evict_inode(struct inode *inode)
|
||||
if (HOSTFS_I(inode)->fd != -1) {
|
||||
close_file(&HOSTFS_I(inode)->fd);
|
||||
HOSTFS_I(inode)->fd = -1;
|
||||
HOSTFS_I(inode)->dev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,6 +260,7 @@ static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
|
||||
static const struct super_operations hostfs_sbops = {
|
||||
.alloc_inode = hostfs_alloc_inode,
|
||||
.free_inode = hostfs_free_inode,
|
||||
.drop_inode = generic_delete_inode,
|
||||
.evict_inode = hostfs_evict_inode,
|
||||
.statfs = hostfs_statfs,
|
||||
.show_options = hostfs_show_options,
|
||||
@@ -512,18 +508,31 @@ static const struct address_space_operations hostfs_aops = {
|
||||
.write_end = hostfs_write_end,
|
||||
};
|
||||
|
||||
static int read_name(struct inode *ino, char *name)
|
||||
static int hostfs_inode_update(struct inode *ino, const struct hostfs_stat *st)
|
||||
{
|
||||
set_nlink(ino, st->nlink);
|
||||
i_uid_write(ino, st->uid);
|
||||
i_gid_write(ino, st->gid);
|
||||
ino->i_atime =
|
||||
(struct timespec64){ st->atime.tv_sec, st->atime.tv_nsec };
|
||||
ino->i_mtime =
|
||||
(struct timespec64){ st->mtime.tv_sec, st->mtime.tv_nsec };
|
||||
ino->i_ctime =
|
||||
(struct timespec64){ st->ctime.tv_sec, st->ctime.tv_nsec };
|
||||
ino->i_size = st->size;
|
||||
ino->i_blocks = st->blocks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hostfs_inode_set(struct inode *ino, void *data)
|
||||
{
|
||||
struct hostfs_stat *st = data;
|
||||
dev_t rdev;
|
||||
struct hostfs_stat st;
|
||||
int err = stat_file(name, &st, -1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Reencode maj and min with the kernel encoding.*/
|
||||
rdev = MKDEV(st.maj, st.min);
|
||||
rdev = MKDEV(st->maj, st->min);
|
||||
|
||||
switch (st.mode & S_IFMT) {
|
||||
switch (st->mode & S_IFMT) {
|
||||
case S_IFLNK:
|
||||
ino->i_op = &hostfs_link_iops;
|
||||
break;
|
||||
@@ -535,7 +544,7 @@ static int read_name(struct inode *ino, char *name)
|
||||
case S_IFBLK:
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
init_special_inode(ino, st.mode & S_IFMT, rdev);
|
||||
init_special_inode(ino, st->mode & S_IFMT, rdev);
|
||||
ino->i_op = &hostfs_iops;
|
||||
break;
|
||||
case S_IFREG:
|
||||
@@ -547,17 +556,42 @@ static int read_name(struct inode *ino, char *name)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ino->i_ino = st.ino;
|
||||
ino->i_mode = st.mode;
|
||||
set_nlink(ino, st.nlink);
|
||||
i_uid_write(ino, st.uid);
|
||||
i_gid_write(ino, st.gid);
|
||||
ino->i_atime = (struct timespec64){ st.atime.tv_sec, st.atime.tv_nsec };
|
||||
ino->i_mtime = (struct timespec64){ st.mtime.tv_sec, st.mtime.tv_nsec };
|
||||
ino->i_ctime = (struct timespec64){ st.ctime.tv_sec, st.ctime.tv_nsec };
|
||||
ino->i_size = st.size;
|
||||
ino->i_blocks = st.blocks;
|
||||
return 0;
|
||||
HOSTFS_I(ino)->dev = st->dev;
|
||||
ino->i_ino = st->ino;
|
||||
ino->i_mode = st->mode;
|
||||
return hostfs_inode_update(ino, st);
|
||||
}
|
||||
|
||||
static int hostfs_inode_test(struct inode *inode, void *data)
|
||||
{
|
||||
const struct hostfs_stat *st = data;
|
||||
|
||||
return inode->i_ino == st->ino && HOSTFS_I(inode)->dev == st->dev;
|
||||
}
|
||||
|
||||
static struct inode *hostfs_iget(struct super_block *sb, char *name)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct hostfs_stat st;
|
||||
int err = stat_file(name, &st, -1);
|
||||
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
inode = iget5_locked(sb, st.ino, hostfs_inode_test, hostfs_inode_set,
|
||||
&st);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (inode->i_state & I_NEW) {
|
||||
unlock_new_inode(inode);
|
||||
} else {
|
||||
spin_lock(&inode->i_lock);
|
||||
hostfs_inode_update(inode, &st);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
|
||||
@@ -565,62 +599,48 @@ static int hostfs_create(struct mnt_idmap *idmap, struct inode *dir,
|
||||
{
|
||||
struct inode *inode;
|
||||
char *name;
|
||||
int error, fd;
|
||||
int fd;
|
||||
|
||||
inode = hostfs_iget(dir->i_sb);
|
||||
if (IS_ERR(inode)) {
|
||||
error = PTR_ERR(inode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = -ENOMEM;
|
||||
name = dentry_name(dentry);
|
||||
if (name == NULL)
|
||||
goto out_put;
|
||||
return -ENOMEM;
|
||||
|
||||
fd = file_create(name, mode & 0777);
|
||||
if (fd < 0)
|
||||
error = fd;
|
||||
else
|
||||
error = read_name(inode, name);
|
||||
if (fd < 0) {
|
||||
__putname(name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
inode = hostfs_iget(dir->i_sb, name);
|
||||
__putname(name);
|
||||
if (error)
|
||||
goto out_put;
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
HOSTFS_I(inode)->fd = fd;
|
||||
HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
|
||||
out_put:
|
||||
iput(inode);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct inode *inode = NULL;
|
||||
char *name;
|
||||
int err;
|
||||
|
||||
inode = hostfs_iget(ino->i_sb);
|
||||
if (IS_ERR(inode))
|
||||
goto out;
|
||||
|
||||
err = -ENOMEM;
|
||||
name = dentry_name(dentry);
|
||||
if (name) {
|
||||
err = read_name(inode, name);
|
||||
__putname(name);
|
||||
if (name == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
inode = hostfs_iget(ino->i_sb, name);
|
||||
__putname(name);
|
||||
if (IS_ERR(inode)) {
|
||||
if (PTR_ERR(inode) == -ENOENT)
|
||||
inode = NULL;
|
||||
else
|
||||
return ERR_CAST(inode);
|
||||
}
|
||||
if (err) {
|
||||
iput(inode);
|
||||
inode = (err == -ENOENT) ? NULL : ERR_PTR(err);
|
||||
}
|
||||
out:
|
||||
|
||||
return d_splice_alias(inode, dentry);
|
||||
}
|
||||
|
||||
@@ -704,35 +724,23 @@ static int hostfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
||||
char *name;
|
||||
int err;
|
||||
|
||||
inode = hostfs_iget(dir->i_sb);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
name = dentry_name(dentry);
|
||||
if (name == NULL)
|
||||
goto out_put;
|
||||
return -ENOMEM;
|
||||
|
||||
err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
|
||||
if (err)
|
||||
goto out_free;
|
||||
if (err) {
|
||||
__putname(name);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = read_name(inode, name);
|
||||
inode = hostfs_iget(dir->i_sb, name);
|
||||
__putname(name);
|
||||
if (err)
|
||||
goto out_put;
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
__putname(name);
|
||||
out_put:
|
||||
iput(inode);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hostfs_rename2(struct mnt_idmap *idmap,
|
||||
@@ -929,49 +937,40 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
err = super_setup_bdi(sb);
|
||||
if (err)
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
/* NULL is printed as '(null)' by printf(): avoid that. */
|
||||
if (req_root == NULL)
|
||||
req_root = "";
|
||||
|
||||
err = -ENOMEM;
|
||||
sb->s_fs_info = host_root_path =
|
||||
kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
|
||||
if (host_root_path == NULL)
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
|
||||
root_inode = new_inode(sb);
|
||||
if (!root_inode)
|
||||
goto out;
|
||||
|
||||
err = read_name(root_inode, host_root_path);
|
||||
if (err)
|
||||
goto out_put;
|
||||
root_inode = hostfs_iget(sb, host_root_path);
|
||||
if (IS_ERR(root_inode))
|
||||
return PTR_ERR(root_inode);
|
||||
|
||||
if (S_ISLNK(root_inode->i_mode)) {
|
||||
char *name = follow_link(host_root_path);
|
||||
if (IS_ERR(name)) {
|
||||
err = PTR_ERR(name);
|
||||
goto out_put;
|
||||
}
|
||||
err = read_name(root_inode, name);
|
||||
char *name;
|
||||
|
||||
iput(root_inode);
|
||||
name = follow_link(host_root_path);
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
|
||||
root_inode = hostfs_iget(sb, name);
|
||||
kfree(name);
|
||||
if (err)
|
||||
goto out_put;
|
||||
if (IS_ERR(root_inode))
|
||||
return PTR_ERR(root_inode);
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
sb->s_root = d_make_root(root_inode);
|
||||
if (sb->s_root == NULL)
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
|
||||
out_put:
|
||||
iput(root_inode);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct dentry *hostfs_read_sb(struct file_system_type *type,
|
||||
|
||||
@@ -36,6 +36,7 @@ static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p)
|
||||
p->blocks = buf->st_blocks;
|
||||
p->maj = os_major(buf->st_rdev);
|
||||
p->min = os_minor(buf->st_rdev);
|
||||
p->dev = buf->st_dev;
|
||||
}
|
||||
|
||||
int stat_file(const char *path, struct hostfs_stat *p, int fd)
|
||||
|
||||
+2
-2
@@ -877,7 +877,7 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
|
||||
phdr.p_offset = roundup(note_off, PAGE_SIZE);
|
||||
phdr.p_vaddr = phdr.p_paddr = 0;
|
||||
phdr.p_filesz = phdr.p_memsz = phdr_sz;
|
||||
phdr.p_align = 0;
|
||||
phdr.p_align = 4;
|
||||
|
||||
/* Add merged PT_NOTE program header*/
|
||||
tmp = elfptr + sizeof(Elf64_Ehdr);
|
||||
@@ -1068,7 +1068,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
|
||||
phdr.p_offset = roundup(note_off, PAGE_SIZE);
|
||||
phdr.p_vaddr = phdr.p_paddr = 0;
|
||||
phdr.p_filesz = phdr.p_memsz = phdr_sz;
|
||||
phdr.p_align = 0;
|
||||
phdr.p_align = 4;
|
||||
|
||||
/* Add merged PT_NOTE program header*/
|
||||
tmp = elfptr + sizeof(Elf32_Ehdr);
|
||||
|
||||
+2
-4
@@ -875,7 +875,7 @@ fail_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ramoops_remove(struct platform_device *pdev)
|
||||
static void ramoops_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ramoops_context *cxt = &oops_cxt;
|
||||
|
||||
@@ -885,8 +885,6 @@ static int ramoops_remove(struct platform_device *pdev)
|
||||
cxt->pstore.bufsize = 0;
|
||||
|
||||
ramoops_free_przs(cxt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id dt_match[] = {
|
||||
@@ -896,7 +894,7 @@ static const struct of_device_id dt_match[] = {
|
||||
|
||||
static struct platform_driver ramoops_driver = {
|
||||
.probe = ramoops_probe,
|
||||
.remove = ramoops_remove,
|
||||
.remove_new = ramoops_remove,
|
||||
.driver = {
|
||||
.name = "ramoops",
|
||||
.of_match_table = dt_match,
|
||||
|
||||
@@ -599,6 +599,8 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
|
||||
raw_spin_lock_init(&prz->buffer_lock);
|
||||
prz->flags = flags;
|
||||
prz->label = kstrdup(label, GFP_KERNEL);
|
||||
if (!prz->label)
|
||||
goto err;
|
||||
|
||||
ret = persistent_ram_buffer_map(start, size, prz, memtype);
|
||||
if (ret)
|
||||
|
||||
@@ -67,6 +67,7 @@ int reiserfs_security_init(struct inode *dir, struct inode *inode,
|
||||
|
||||
sec->name = NULL;
|
||||
sec->value = NULL;
|
||||
sec->length = 0;
|
||||
|
||||
/* Don't add selinux attributes on xattrs - they'll never get used */
|
||||
if (IS_PRIVATE(dir))
|
||||
|
||||
@@ -130,8 +130,6 @@ extern unsigned compat_dir_class[];
|
||||
extern unsigned compat_chattr_class[];
|
||||
extern unsigned compat_signal_class[];
|
||||
|
||||
extern int audit_classify_compat_syscall(int abi, unsigned syscall);
|
||||
|
||||
/* audit_names->type values */
|
||||
#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
|
||||
#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
|
||||
|
||||
@@ -21,4 +21,6 @@ enum auditsc_class_t {
|
||||
AUDITSC_NVALS /* count */
|
||||
};
|
||||
|
||||
extern int audit_classify_compat_syscall(int abi, unsigned syscall);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -343,6 +343,7 @@ LSM_HOOK(void, LSM_RET_VOID, sctp_sk_clone, struct sctp_association *asoc,
|
||||
struct sock *sk, struct sock *newsk)
|
||||
LSM_HOOK(int, 0, sctp_assoc_established, struct sctp_association *asoc,
|
||||
struct sk_buff *skb)
|
||||
LSM_HOOK(int, 0, mptcp_add_subflow, struct sock *sk, struct sock *ssk)
|
||||
#endif /* CONFIG_SECURITY_NETWORK */
|
||||
|
||||
#ifdef CONFIG_SECURITY_INFINIBAND
|
||||
|
||||
@@ -1465,6 +1465,7 @@ void security_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk,
|
||||
struct sock *newsk);
|
||||
int security_sctp_assoc_established(struct sctp_association *asoc,
|
||||
struct sk_buff *skb);
|
||||
int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk);
|
||||
|
||||
#else /* CONFIG_SECURITY_NETWORK */
|
||||
static inline int security_unix_stream_connect(struct sock *sock,
|
||||
@@ -1692,6 +1693,11 @@ static inline int security_sctp_assoc_established(struct sctp_association *asoc,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SECURITY_NETWORK */
|
||||
|
||||
#ifdef CONFIG_SECURITY_INFINIBAND
|
||||
|
||||
@@ -41,11 +41,12 @@ typedef struct __user_cap_header_struct {
|
||||
int pid;
|
||||
} __user *cap_user_header_t;
|
||||
|
||||
typedef struct __user_cap_data_struct {
|
||||
struct __user_cap_data_struct {
|
||||
__u32 effective;
|
||||
__u32 permitted;
|
||||
__u32 inheritable;
|
||||
} __user *cap_user_data_t;
|
||||
};
|
||||
typedef struct __user_cap_data_struct __user *cap_user_data_t;
|
||||
|
||||
|
||||
#define VFS_CAP_REVISION_MASK 0xFF000000
|
||||
|
||||
@@ -372,7 +372,8 @@ typedef struct elf64_shdr {
|
||||
* Notes used in ET_CORE. Architectures export some of the arch register sets
|
||||
* using the corresponding note types via the PTRACE_GETREGSET and
|
||||
* PTRACE_SETREGSET requests.
|
||||
* The note name for all these is "LINUX".
|
||||
* The note name for these types is "LINUX", except NT_PRFPREG that is named
|
||||
* "CORE".
|
||||
*/
|
||||
#define NT_PRSTATUS 1
|
||||
#define NT_PRFPREG 2
|
||||
|
||||
+1
-1
@@ -259,8 +259,8 @@ extern struct tty_struct *audit_get_tty(void);
|
||||
extern void audit_put_tty(struct tty_struct *tty);
|
||||
|
||||
/* audit watch/mark/tree functions */
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
extern unsigned int audit_serial(void);
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
extern int auditsc_get_stamp(struct audit_context *ctx,
|
||||
struct timespec64 *t, unsigned int *serial);
|
||||
|
||||
|
||||
@@ -467,6 +467,7 @@ EXPORT_SYMBOL(file_ns_capable);
|
||||
/**
|
||||
* privileged_wrt_inode_uidgid - Do capabilities in the namespace work over the inode?
|
||||
* @ns: The user namespace in question
|
||||
* @idmap: idmap of the mount @inode was found from
|
||||
* @inode: The inode in question
|
||||
*
|
||||
* Return true if the inode uid and gid are within the namespace.
|
||||
@@ -481,6 +482,7 @@ bool privileged_wrt_inode_uidgid(struct user_namespace *ns,
|
||||
|
||||
/**
|
||||
* capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped
|
||||
* @idmap: idmap of the mount @inode was found from
|
||||
* @inode: The inode in question
|
||||
* @cap: The capability in question
|
||||
*
|
||||
|
||||
@@ -1668,6 +1668,10 @@ int mptcp_subflow_create_socket(struct sock *sk, unsigned short family,
|
||||
|
||||
lock_sock_nested(sf->sk, SINGLE_DEPTH_NESTING);
|
||||
|
||||
err = security_mptcp_add_subflow(sk, sf->sk);
|
||||
if (err)
|
||||
goto release_ssk;
|
||||
|
||||
/* the newly created socket has to be in the same cgroup as its parent */
|
||||
mptcp_attach_cgroup(sk, sf->sk);
|
||||
|
||||
@@ -1680,6 +1684,8 @@ int mptcp_subflow_create_socket(struct sock *sk, unsigned short family,
|
||||
get_net_track(net, &sf->sk->ns_tracker, GFP_KERNEL);
|
||||
sock_inuse_add(net, 1);
|
||||
err = tcp_set_ulp(sf->sk, "mptcp");
|
||||
|
||||
release_ssk:
|
||||
release_sock(sf->sk);
|
||||
|
||||
if (err) {
|
||||
|
||||
+10
-10
@@ -314,7 +314,7 @@ int cap_inode_need_killpriv(struct dentry *dentry)
|
||||
* the vfsmount must be passed through @idmap. This function will then
|
||||
* take care to map the inode according to @idmap before checking
|
||||
* permissions. On non-idmapped mounts or if permission checking is to be
|
||||
* performed on the raw inode simply passs @nop_mnt_idmap.
|
||||
* performed on the raw inode simply pass @nop_mnt_idmap.
|
||||
*
|
||||
* Return: 0 if successful, -ve on error.
|
||||
*/
|
||||
@@ -522,7 +522,7 @@ static bool validheader(size_t size, const struct vfs_cap_data *cap)
|
||||
* the vfsmount must be passed through @idmap. This function will then
|
||||
* take care to map the inode according to @idmap before checking
|
||||
* permissions. On non-idmapped mounts or if permission checking is to be
|
||||
* performed on the raw inode simply passs @nop_mnt_idmap.
|
||||
* performed on the raw inode simply pass @nop_mnt_idmap.
|
||||
*
|
||||
* Return: On success, return the new size; on error, return < 0.
|
||||
*/
|
||||
@@ -630,7 +630,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
|
||||
* the vfsmount must be passed through @idmap. This function will then
|
||||
* take care to map the inode according to @idmap before checking
|
||||
* permissions. On non-idmapped mounts or if permission checking is to be
|
||||
* performed on the raw inode simply passs @nop_mnt_idmap.
|
||||
* performed on the raw inode simply pass @nop_mnt_idmap.
|
||||
*/
|
||||
int get_vfs_caps_from_disk(struct mnt_idmap *idmap,
|
||||
const struct dentry *dentry,
|
||||
@@ -1133,7 +1133,7 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
|
||||
break;
|
||||
|
||||
case LSM_SETID_FS:
|
||||
/* juggle the capabilties to follow FSUID changes, unless
|
||||
/* juggle the capabilities to follow FSUID changes, unless
|
||||
* otherwise suppressed
|
||||
*
|
||||
* FIXME - is fsuser used for all CAP_FS_MASK capabilities?
|
||||
@@ -1184,10 +1184,10 @@ static int cap_safe_nice(struct task_struct *p)
|
||||
}
|
||||
|
||||
/**
|
||||
* cap_task_setscheduler - Detemine if scheduler policy change is permitted
|
||||
* cap_task_setscheduler - Determine if scheduler policy change is permitted
|
||||
* @p: The task to affect
|
||||
*
|
||||
* Detemine if the requested scheduler policy change is permitted for the
|
||||
* Determine if the requested scheduler policy change is permitted for the
|
||||
* specified task.
|
||||
*
|
||||
* Return: 0 if permission is granted, -ve if denied.
|
||||
@@ -1198,11 +1198,11 @@ int cap_task_setscheduler(struct task_struct *p)
|
||||
}
|
||||
|
||||
/**
|
||||
* cap_task_setioprio - Detemine if I/O priority change is permitted
|
||||
* cap_task_setioprio - Determine if I/O priority change is permitted
|
||||
* @p: The task to affect
|
||||
* @ioprio: The I/O priority to set
|
||||
*
|
||||
* Detemine if the requested I/O priority change is permitted for the specified
|
||||
* Determine if the requested I/O priority change is permitted for the specified
|
||||
* task.
|
||||
*
|
||||
* Return: 0 if permission is granted, -ve if denied.
|
||||
@@ -1213,11 +1213,11 @@ int cap_task_setioprio(struct task_struct *p, int ioprio)
|
||||
}
|
||||
|
||||
/**
|
||||
* cap_task_setnice - Detemine if task priority change is permitted
|
||||
* cap_task_setnice - Determine if task priority change is permitted
|
||||
* @p: The task to affect
|
||||
* @nice: The nice value to set
|
||||
*
|
||||
* Detemine if the requested task priority change is permitted for the
|
||||
* Determine if the requested task priority change is permitted for the
|
||||
* specified task.
|
||||
*
|
||||
* Return: 0 if permission is granted, -ve if denied.
|
||||
|
||||
@@ -421,7 +421,7 @@ static bool verify_new_ex(struct dev_cgroup *dev_cgroup,
|
||||
} else {
|
||||
/*
|
||||
* new exception in the child will add more devices
|
||||
* that can be acessed, so it can't match any of
|
||||
* that can be accessed, so it can't match any of
|
||||
* parent's exceptions, even slightly
|
||||
*/
|
||||
match = match_exception_partial(&dev_cgroup->exceptions,
|
||||
@@ -822,7 +822,6 @@ struct cgroup_subsys devices_cgrp_subsys = {
|
||||
|
||||
/**
|
||||
* devcgroup_legacy_check_permission - checks if an inode operation is permitted
|
||||
* @dev_cgroup: the dev cgroup to be tested against
|
||||
* @type: device type
|
||||
* @major: device major number
|
||||
* @minor: device minor number
|
||||
|
||||
@@ -40,7 +40,7 @@ static const char evm_hmac[] = "hmac(sha1)";
|
||||
/**
|
||||
* evm_set_key() - set EVM HMAC key from the kernel
|
||||
* @key: pointer to a buffer with the key data
|
||||
* @size: length of the key data
|
||||
* @keylen: length of the key data
|
||||
*
|
||||
* This function allows setting the EVM HMAC key from the kernel
|
||||
* without using the "encrypted" key subsystem keys. It can be used
|
||||
|
||||
@@ -318,7 +318,6 @@ int evm_protected_xattr_if_enabled(const char *req_xattr_name)
|
||||
/**
|
||||
* evm_read_protected_xattrs - read EVM protected xattr names, lengths, values
|
||||
* @dentry: dentry of the read xattrs
|
||||
* @inode: inode of the read xattrs
|
||||
* @buffer: buffer xattr names, lengths or values are copied to
|
||||
* @buffer_size: size of buffer
|
||||
* @type: n: names, l: lengths, v: values
|
||||
@@ -390,6 +389,7 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
|
||||
* @xattr_name: requested xattr
|
||||
* @xattr_value: requested xattr value
|
||||
* @xattr_value_len: requested xattr value length
|
||||
* @iint: inode integrity metadata
|
||||
*
|
||||
* Calculate the HMAC for the given dentry and verify it against the stored
|
||||
* security.evm xattr. For performance, use the xattr value and length
|
||||
@@ -795,7 +795,9 @@ static int evm_attr_change(struct mnt_idmap *idmap,
|
||||
|
||||
/**
|
||||
* evm_inode_setattr - prevent updating an invalid EVM extended attribute
|
||||
* @idmap: idmap of the mount
|
||||
* @dentry: pointer to the affected dentry
|
||||
* @attr: iattr structure containing the new file attributes
|
||||
*
|
||||
* Permit update of file attributes when files have a valid EVM signature,
|
||||
* except in the case of them having an immutable portable signature.
|
||||
|
||||
@@ -43,12 +43,10 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
|
||||
else if (inode > iint->inode)
|
||||
n = n->rb_right;
|
||||
else
|
||||
break;
|
||||
return iint;
|
||||
}
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
return iint;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -113,10 +111,15 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
|
||||
parent = *p;
|
||||
test_iint = rb_entry(parent, struct integrity_iint_cache,
|
||||
rb_node);
|
||||
if (inode < test_iint->inode)
|
||||
if (inode < test_iint->inode) {
|
||||
p = &(*p)->rb_left;
|
||||
else
|
||||
} else if (inode > test_iint->inode) {
|
||||
p = &(*p)->rb_right;
|
||||
} else {
|
||||
write_unlock(&integrity_iint_lock);
|
||||
kmem_cache_free(iint_cache, iint);
|
||||
return test_iint;
|
||||
}
|
||||
}
|
||||
|
||||
iint->inode = inode;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/evm.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/fsverity.h>
|
||||
|
||||
#include "ima.h"
|
||||
@@ -246,10 +245,11 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
struct inode *inode = file_inode(file);
|
||||
const char *filename = file->f_path.dentry->d_name.name;
|
||||
struct ima_max_digest_data hash;
|
||||
struct kstat stat;
|
||||
int result = 0;
|
||||
int length;
|
||||
void *tmpbuf;
|
||||
u64 i_version;
|
||||
u64 i_version = 0;
|
||||
|
||||
/*
|
||||
* Always collect the modsig, because IMA might have already collected
|
||||
@@ -268,7 +268,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
* to an initial measurement/appraisal/audit, but was modified to
|
||||
* assume the file changed.
|
||||
*/
|
||||
i_version = inode_query_iversion(inode);
|
||||
result = vfs_getattr_nosec(&file->f_path, &stat, STATX_CHANGE_COOKIE,
|
||||
AT_STATX_SYNC_AS_STAT);
|
||||
if (!result && (stat.result_mask & STATX_CHANGE_COOKIE))
|
||||
i_version = stat.change_cookie;
|
||||
hash.hdr.algo = algo;
|
||||
hash.hdr.length = hash_digest_size[algo];
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/ima.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "ima.h"
|
||||
@@ -164,11 +163,16 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
|
||||
|
||||
mutex_lock(&iint->mutex);
|
||||
if (atomic_read(&inode->i_writecount) == 1) {
|
||||
struct kstat stat;
|
||||
|
||||
update = test_and_clear_bit(IMA_UPDATE_XATTR,
|
||||
&iint->atomic_flags);
|
||||
if (!IS_I_VERSION(inode) ||
|
||||
!inode_eq_iversion(inode, iint->version) ||
|
||||
(iint->flags & IMA_NEW_FILE)) {
|
||||
if ((iint->flags & IMA_NEW_FILE) ||
|
||||
vfs_getattr_nosec(&file->f_path, &stat,
|
||||
STATX_CHANGE_COOKIE,
|
||||
AT_STATX_SYNC_AS_STAT) ||
|
||||
!(stat.result_mask & STATX_CHANGE_COOKIE) ||
|
||||
stat.change_cookie != iint->version) {
|
||||
iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
|
||||
iint->measured_pcrs = 0;
|
||||
if (update)
|
||||
|
||||
@@ -89,6 +89,9 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
||||
|
||||
/**
|
||||
* ima_collect_modsig - Calculate the file hash without the appended signature.
|
||||
* @modsig: parsed module signature
|
||||
* @buf: data to verify the signature on
|
||||
* @size: data size
|
||||
*
|
||||
* Since the modsig is part of the file contents, the hash used in its signature
|
||||
* isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code
|
||||
|
||||
@@ -721,6 +721,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
|
||||
* @secid: LSM secid of the task to be validated
|
||||
* @func: IMA hook identifier
|
||||
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
|
||||
* @flags: IMA actions to consider (e.g. IMA_MEASURE | IMA_APPRAISE)
|
||||
* @pcr: set the pcr to extend
|
||||
* @template_desc: the template that should be used for this rule
|
||||
* @func_data: func specific data, may be NULL
|
||||
@@ -1915,7 +1916,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||
|
||||
/**
|
||||
* ima_parse_add_rule - add a rule to ima_policy_rules
|
||||
* @rule - ima measurement policy rule
|
||||
* @rule: ima measurement policy rule
|
||||
*
|
||||
* Avoid locking by allowing just one writer at a time in ima_write_policy()
|
||||
* Returns the length of the rule parsed, an error code on failure
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
config SECURITY_LANDLOCK
|
||||
bool "Landlock support"
|
||||
depends on SECURITY && !ARCH_EPHEMERAL_INODES
|
||||
depends on SECURITY
|
||||
select SECURITY_PATH
|
||||
help
|
||||
Landlock is a sandboxing mechanism that enables processes to restrict
|
||||
|
||||
@@ -200,7 +200,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
|
||||
char comm[sizeof(current->comm)];
|
||||
|
||||
/*
|
||||
* To keep stack sizes in check force programers to notice if they
|
||||
* To keep stack sizes in check force programmers to notice if they
|
||||
* start making this union too large! See struct lsm_network_audit
|
||||
* as an example of how to deal with large data.
|
||||
*/
|
||||
|
||||
@@ -131,7 +131,7 @@ static int safesetid_security_capable(const struct cred *cred,
|
||||
* set*gid() (e.g. setting up userns gid mappings).
|
||||
*/
|
||||
pr_warn("Operation requires CAP_SETGID, which is not available to GID %u for operations besides approved set*gid transitions\n",
|
||||
__kuid_val(cred->uid));
|
||||
__kgid_val(cred->gid));
|
||||
return -EPERM;
|
||||
default:
|
||||
/* Error, the only capabilities were checking for is CAP_SETUID/GID */
|
||||
|
||||
+19
-2
@@ -2491,7 +2491,7 @@ int security_inode_copy_up_xattr(const char *name)
|
||||
/*
|
||||
* The implementation can return 0 (accept the xattr), 1 (discard the
|
||||
* xattr), -EOPNOTSUPP if it does not know anything about the xattr or
|
||||
* any other error code incase of an error.
|
||||
* any other error code in case of an error.
|
||||
*/
|
||||
hlist_for_each_entry(hp,
|
||||
&security_hook_heads.inode_copy_up_xattr, list) {
|
||||
@@ -4667,6 +4667,23 @@ int security_sctp_assoc_established(struct sctp_association *asoc,
|
||||
}
|
||||
EXPORT_SYMBOL(security_sctp_assoc_established);
|
||||
|
||||
/**
|
||||
* security_mptcp_add_subflow() - Inherit the LSM label from the MPTCP socket
|
||||
* @sk: the owning MPTCP socket
|
||||
* @ssk: the new subflow
|
||||
*
|
||||
* Update the labeling for the given MPTCP subflow, to match the one of the
|
||||
* owning MPTCP socket. This hook has to be called after the socket creation and
|
||||
* initialization via the security_socket_create() and
|
||||
* security_socket_post_create() LSM hooks.
|
||||
*
|
||||
* Return: Returns 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
|
||||
{
|
||||
return call_int_hook(mptcp_add_subflow, 0, sk, ssk);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SECURITY_NETWORK */
|
||||
|
||||
#ifdef CONFIG_SECURITY_INFINIBAND
|
||||
@@ -4676,7 +4693,7 @@ EXPORT_SYMBOL(security_sctp_assoc_established);
|
||||
* @subnet_prefix: subnet prefix of the port
|
||||
* @pkey: IB pkey
|
||||
*
|
||||
* Check permission to access a pkey when modifing a QP.
|
||||
* Check permission to access a pkey when modifying a QP.
|
||||
*
|
||||
* Return: Returns 0 if permission is granted.
|
||||
*/
|
||||
|
||||
+18
-12
@@ -3,32 +3,38 @@
|
||||
# Makefile for building the SELinux module as part of the kernel tree.
|
||||
#
|
||||
|
||||
# NOTE: There are a number of improvements that can be made to this Makefile
|
||||
# once the kernel requires make v4.3 or greater; the most important feature
|
||||
# lacking in older versions of make is support for grouped targets. These
|
||||
# improvements are noted inline in the Makefile below ...
|
||||
|
||||
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
|
||||
|
||||
ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
|
||||
|
||||
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
|
||||
netnode.o netport.o status.o \
|
||||
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
|
||||
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
|
||||
|
||||
selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
|
||||
|
||||
selinux-$(CONFIG_NETLABEL) += netlabel.o
|
||||
|
||||
selinux-$(CONFIG_SECURITY_INFINIBAND) += ibpkey.o
|
||||
|
||||
selinux-$(CONFIG_IMA) += ima.o
|
||||
|
||||
ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
|
||||
genhdrs := flask.h av_permissions.h
|
||||
|
||||
# see the note above, replace the dependency rule with the one below:
|
||||
# $(addprefix $(obj)/,$(selinux-y)): $(addprefix $(obj)/,$(genhdrs))
|
||||
$(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
|
||||
|
||||
quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h
|
||||
cmd_flask = $< $(obj)/flask.h $(obj)/av_permissions.h
|
||||
quiet_cmd_genhdrs = GEN $(addprefix $(obj)/,$(genhdrs))
|
||||
cmd_genhdrs = $< $(addprefix $(obj)/,$(genhdrs))
|
||||
|
||||
targets += flask.h av_permissions.h
|
||||
# once make >= 4.3 is required, we can use grouped targets in the rule below,
|
||||
# which basically involves adding both headers and a '&' before the colon, see
|
||||
# the example below:
|
||||
# $(obj)/flask.h $(obj)/av_permissions.h &: scripts/selinux/...
|
||||
# see the note above, replace the $targets and 'flask.h' rule with the lines
|
||||
# below:
|
||||
# targets += $(genhdrs)
|
||||
# $(addprefix $(obj)/,$(genhdrs)) &: scripts/selinux/...
|
||||
targets += flask.h
|
||||
$(obj)/flask.h: scripts/selinux/genheaders/genheaders FORCE
|
||||
$(call if_changed,flask)
|
||||
$(call if_changed,genhdrs)
|
||||
|
||||
@@ -650,7 +650,6 @@ static void avc_insert(u32 ssid, u32 tsid, u16 tclass,
|
||||
trace_android_rvh_selinux_avc_insert(node);
|
||||
found:
|
||||
spin_unlock_irqrestore(lock, flag);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1211,22 +1210,3 @@ u32 avc_policy_seqno(void)
|
||||
{
|
||||
return selinux_avc.avc_cache.latest_notif;
|
||||
}
|
||||
|
||||
void avc_disable(void)
|
||||
{
|
||||
/*
|
||||
* If you are looking at this because you have realized that we are
|
||||
* not destroying the avc_node_cachep it might be easy to fix, but
|
||||
* I don't know the memory barrier semantics well enough to know. It's
|
||||
* possible that some other task dereferenced security_ops when
|
||||
* it still pointed to selinux operations. If that is the case it's
|
||||
* possible that it is about to use the avc and is about to need the
|
||||
* avc_node_cachep. I know I could wrap the security.c security_ops call
|
||||
* in an rcu_lock, but seriously, it's not worth it. Instead I just flush
|
||||
* the cache and get that memory back.
|
||||
*/
|
||||
if (avc_node_cachep) {
|
||||
avc_flush();
|
||||
/* kmem_cache_destroy(avc_node_cachep); */
|
||||
}
|
||||
}
|
||||
|
||||
+59
-19
@@ -357,7 +357,7 @@ enum {
|
||||
};
|
||||
|
||||
#define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
|
||||
static struct {
|
||||
static const struct {
|
||||
const char *name;
|
||||
int len;
|
||||
int opt;
|
||||
@@ -605,6 +605,13 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
||||
u32 defcontext_sid = 0;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
* Specifying internal flags without providing a place to
|
||||
* place the results is not allowed
|
||||
*/
|
||||
if (kern_flags && !set_kern_flags)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&sbsec->lock);
|
||||
|
||||
if (!selinux_initialized()) {
|
||||
@@ -612,6 +619,10 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
||||
/* Defer initialization until selinux_complete_init,
|
||||
after the initial policy is loaded and the security
|
||||
server is ready to handle calls. */
|
||||
if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
|
||||
sbsec->flags |= SE_SBNATIVE;
|
||||
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
rc = -EINVAL;
|
||||
@@ -619,12 +630,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
||||
"before the security server is initialized\n");
|
||||
goto out;
|
||||
}
|
||||
if (kern_flags && !set_kern_flags) {
|
||||
/* Specifying internal flags without providing a place to
|
||||
* place the results is not allowed */
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary mount data FS will come through this function twice. Once
|
||||
@@ -757,7 +762,17 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
||||
* sets the label used on all file below the mountpoint, and will set
|
||||
* the superblock context if not already set.
|
||||
*/
|
||||
if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
|
||||
if (sbsec->flags & SE_SBNATIVE) {
|
||||
/*
|
||||
* This means we are initializing a superblock that has been
|
||||
* mounted before the SELinux was initialized and the
|
||||
* filesystem requested native labeling. We had already
|
||||
* returned SECURITY_LSM_NATIVE_LABELS in *set_kern_flags
|
||||
* in the original mount attempt, so now we just need to set
|
||||
* the SECURITY_FS_USE_NATIVE behavior.
|
||||
*/
|
||||
sbsec->behavior = SECURITY_FS_USE_NATIVE;
|
||||
} else if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
|
||||
sbsec->behavior = SECURITY_FS_USE_NATIVE;
|
||||
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
|
||||
}
|
||||
@@ -868,13 +883,6 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||
int set_context = (oldsbsec->flags & CONTEXT_MNT);
|
||||
int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
|
||||
|
||||
/*
|
||||
* if the parent was able to be mounted it clearly had no special lsm
|
||||
* mount options. thus we can safely deal with this superblock later
|
||||
*/
|
||||
if (!selinux_initialized())
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Specifying internal flags without providing a place to
|
||||
* place the results is not allowed.
|
||||
@@ -882,18 +890,31 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||
if (kern_flags && !set_kern_flags)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&newsbsec->lock);
|
||||
|
||||
/*
|
||||
* if the parent was able to be mounted it clearly had no special lsm
|
||||
* mount options. thus we can safely deal with this superblock later
|
||||
*/
|
||||
if (!selinux_initialized()) {
|
||||
if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
|
||||
newsbsec->flags |= SE_SBNATIVE;
|
||||
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* how can we clone if the old one wasn't set up?? */
|
||||
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
|
||||
|
||||
/* if fs is reusing a sb, make sure that the contexts match */
|
||||
if (newsbsec->flags & SE_SBINITIALIZED) {
|
||||
mutex_unlock(&newsbsec->lock);
|
||||
if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
|
||||
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
|
||||
return selinux_cmp_sb_context(oldsb, newsb);
|
||||
}
|
||||
|
||||
mutex_lock(&newsbsec->lock);
|
||||
|
||||
newsbsec->flags = oldsbsec->flags;
|
||||
|
||||
newsbsec->sid = oldsbsec->sid;
|
||||
@@ -937,7 +958,7 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: the caller is resposible for freeing the memory even if on error.
|
||||
* NOTE: the caller is responsible for freeing the memory even if on error.
|
||||
*/
|
||||
static int selinux_add_opt(int token, const char *s, void **mnt_opts)
|
||||
{
|
||||
@@ -1394,8 +1415,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
|
||||
spin_unlock(&isec->lock);
|
||||
|
||||
switch (sbsec->behavior) {
|
||||
/*
|
||||
* In case of SECURITY_FS_USE_NATIVE we need to re-fetch the labels
|
||||
* via xattr when called from delayed_superblock_init().
|
||||
*/
|
||||
case SECURITY_FS_USE_NATIVE:
|
||||
break;
|
||||
case SECURITY_FS_USE_XATTR:
|
||||
if (!(inode->i_opflags & IOP_XATTR)) {
|
||||
sid = sbsec->def_sid;
|
||||
@@ -5379,6 +5403,21 @@ static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk
|
||||
selinux_netlbl_sctp_sk_clone(sk, newsk);
|
||||
}
|
||||
|
||||
static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
|
||||
{
|
||||
struct sk_security_struct *ssksec = ssk->sk_security;
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
|
||||
ssksec->sclass = sksec->sclass;
|
||||
ssksec->sid = sksec->sid;
|
||||
|
||||
/* replace the existing subflow label deleting the existing one
|
||||
* and re-recreating a new label using the updated context
|
||||
*/
|
||||
selinux_netlbl_sk_security_free(ssksec);
|
||||
return selinux_netlbl_socket_post_create(ssk, ssk->sk_family);
|
||||
}
|
||||
|
||||
static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
|
||||
struct request_sock *req)
|
||||
{
|
||||
@@ -7074,6 +7113,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
|
||||
LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
|
||||
LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
|
||||
LSM_HOOK_INIT(sctp_assoc_established, selinux_sctp_assoc_established),
|
||||
LSM_HOOK_INIT(mptcp_add_subflow, selinux_mptcp_add_subflow),
|
||||
LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
|
||||
LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
|
||||
LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
|
||||
*
|
||||
* Measure critical data structures maintainted by SELinux
|
||||
* Measure critical data structures maintained by SELinux
|
||||
* using IMA subsystem.
|
||||
*/
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
@@ -41,7 +41,7 @@ void selinux_audit_rule_free(void *rule);
|
||||
* selinux_audit_rule_match - determine if a context ID matches a rule.
|
||||
* @sid: the context ID to check
|
||||
* @field: the field this rule refers to
|
||||
* @op: the operater the rule uses
|
||||
* @op: the operator the rule uses
|
||||
* @rule: pointer to the audit rule to check against
|
||||
*
|
||||
* Returns 1 if the context id matches the rule, 0 if it does not, and
|
||||
|
||||
@@ -168,9 +168,6 @@ int avc_get_hash_stats(char *page);
|
||||
unsigned int avc_get_cache_threshold(void);
|
||||
void avc_set_cache_threshold(unsigned int cache_threshold);
|
||||
|
||||
/* Attempt to free avc node cache */
|
||||
void avc_disable(void);
|
||||
|
||||
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
|
||||
DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define _SELINUX_IB_PKEY_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "flask.h"
|
||||
|
||||
#ifdef CONFIG_SECURITY_INFINIBAND
|
||||
void sel_ib_pkey_flush(void);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
|
||||
*
|
||||
* Measure critical data structures maintainted by SELinux
|
||||
* Measure critical data structures maintained by SELinux
|
||||
* using IMA subsystem.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <linux/stddef.h>
|
||||
|
||||
static const char *const initial_sid_to_string[] = {
|
||||
NULL,
|
||||
"kernel",
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#define SE_SBPROC 0x0200
|
||||
#define SE_SBGENFS 0x0400
|
||||
#define SE_SBGENFS_XATTR 0x0800
|
||||
#define SE_SBNATIVE 0x1000
|
||||
|
||||
#define CONTEXT_STR "context"
|
||||
#define FSCONTEXT_STR "fscontext"
|
||||
@@ -400,7 +401,6 @@ struct selinux_kernel_status {
|
||||
extern void selinux_status_update_setenforce(int enforcing);
|
||||
extern void selinux_status_update_policyload(int seqno);
|
||||
extern void selinux_complete_init(void);
|
||||
extern void exit_sel_fs(void);
|
||||
extern struct path selinux_null;
|
||||
extern void selnl_notify_setenforce(int val);
|
||||
extern void selnl_notify_policyload(u32 seqno);
|
||||
|
||||
@@ -154,8 +154,12 @@ void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
|
||||
*/
|
||||
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
|
||||
{
|
||||
if (sksec->nlbl_secattr != NULL)
|
||||
netlbl_secattr_free(sksec->nlbl_secattr);
|
||||
if (!sksec->nlbl_secattr)
|
||||
return;
|
||||
|
||||
netlbl_secattr_free(sksec->nlbl_secattr);
|
||||
sksec->nlbl_secattr = NULL;
|
||||
sksec->nlbl_state = NLBL_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -951,7 +951,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
|
||||
* either whitespace or multibyte characters, they shall be
|
||||
* encoded based on the percentage-encoding rule.
|
||||
* If not encoded, the sscanf logic picks up only left-half
|
||||
* of the supplied name; splitted by a whitespace unexpectedly.
|
||||
* of the supplied name; split by a whitespace unexpectedly.
|
||||
*/
|
||||
char *r, *w;
|
||||
int c1, c2;
|
||||
@@ -1649,7 +1649,7 @@ static int sel_make_ss_files(struct dentry *dir)
|
||||
struct super_block *sb = dir->d_sb;
|
||||
struct selinux_fs_info *fsi = sb->s_fs_info;
|
||||
int i;
|
||||
static struct tree_descr files[] = {
|
||||
static const struct tree_descr files[] = {
|
||||
{ "sidtab_hash_stats", &sel_sidtab_hash_stats_ops, S_IRUGO },
|
||||
};
|
||||
|
||||
|
||||
@@ -354,7 +354,7 @@ int avtab_alloc_dup(struct avtab *new, const struct avtab *orig)
|
||||
return avtab_alloc_common(new, orig->nslot);
|
||||
}
|
||||
|
||||
void avtab_hash_eval(struct avtab *h, char *tag)
|
||||
void avtab_hash_eval(struct avtab *h, const char *tag)
|
||||
{
|
||||
int i, chain_len, slots_used, max_chain_len;
|
||||
unsigned long long chain2_len_sum;
|
||||
|
||||
@@ -92,7 +92,7 @@ int avtab_alloc(struct avtab *, u32);
|
||||
int avtab_alloc_dup(struct avtab *new, const struct avtab *orig);
|
||||
struct avtab_datum *avtab_search(struct avtab *h, const struct avtab_key *k);
|
||||
void avtab_destroy(struct avtab *h);
|
||||
void avtab_hash_eval(struct avtab *h, char *tag);
|
||||
void avtab_hash_eval(struct avtab *h, const char *tag);
|
||||
|
||||
struct policydb;
|
||||
int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
|
||||
|
||||
@@ -38,7 +38,7 @@ static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
|
||||
if (sp == (COND_EXPR_MAXDEPTH - 1))
|
||||
return -1;
|
||||
sp++;
|
||||
s[sp] = p->bool_val_to_struct[node->bool - 1]->state;
|
||||
s[sp] = p->bool_val_to_struct[node->boolean - 1]->state;
|
||||
break;
|
||||
case COND_NOT:
|
||||
if (sp < 0)
|
||||
@@ -366,7 +366,7 @@ static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (expr->bool > p->p_bools.nprim) {
|
||||
if (expr->boolean > p->p_bools.nprim) {
|
||||
pr_err("SELinux: conditional expressions uses unknown bool.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -401,7 +401,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
|
||||
return rc;
|
||||
|
||||
expr->expr_type = le32_to_cpu(buf[0]);
|
||||
expr->bool = le32_to_cpu(buf[1]);
|
||||
expr->boolean = le32_to_cpu(buf[1]);
|
||||
|
||||
if (!expr_node_isvalid(p, expr))
|
||||
return -EINVAL;
|
||||
@@ -518,7 +518,7 @@ static int cond_write_node(struct policydb *p, struct cond_node *node,
|
||||
|
||||
for (i = 0; i < node->expr.len; i++) {
|
||||
buf[0] = cpu_to_le32(node->expr.nodes[i].expr_type);
|
||||
buf[1] = cpu_to_le32(node->expr.nodes[i].bool);
|
||||
buf[1] = cpu_to_le32(node->expr.nodes[i].boolean);
|
||||
rc = put_entry(buf, sizeof(u32), 2, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -29,7 +29,7 @@ struct cond_expr_node {
|
||||
#define COND_NEQ 7 /* bool != bool */
|
||||
#define COND_LAST COND_NEQ
|
||||
u32 expr_type;
|
||||
u32 bool;
|
||||
u32 boolean;
|
||||
};
|
||||
|
||||
struct cond_expr {
|
||||
|
||||
@@ -167,6 +167,8 @@ static inline int context_cpy(struct context *dst, const struct context *src)
|
||||
rc = mls_context_cpy(dst, src);
|
||||
if (rc) {
|
||||
kfree(dst->str);
|
||||
dst->str = NULL;
|
||||
dst->len = 0;
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "services.h"
|
||||
|
||||
#ifdef DEBUG_HASHES
|
||||
static const char *symtab_name[SYM_NUM] = {
|
||||
static const char *const symtab_name[SYM_NUM] = {
|
||||
"common prefixes",
|
||||
"classes",
|
||||
"roles",
|
||||
@@ -2257,6 +2257,10 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (i == OCON_FS)
|
||||
pr_warn("SELinux: void and deprecated fs ocon %s\n",
|
||||
c->u.name);
|
||||
|
||||
rc = context_read_and_validate(&c->context[0], p, fp);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
@@ -225,7 +225,7 @@ struct genfs {
|
||||
|
||||
/* object context array indices */
|
||||
#define OCON_ISID 0 /* initial SIDs */
|
||||
#define OCON_FS 1 /* unlabeled file systems */
|
||||
#define OCON_FS 1 /* unlabeled file systems (deprecated) */
|
||||
#define OCON_PORT 2 /* TCP and UDP port numbers */
|
||||
#define OCON_NETIF 3 /* network interfaces */
|
||||
#define OCON_NODE 4 /* nodes */
|
||||
|
||||
@@ -585,7 +585,7 @@ static void type_attribute_bounds_av(struct policydb *policydb,
|
||||
|
||||
/*
|
||||
* flag which drivers have permissions
|
||||
* only looking for ioctl based extended permssions
|
||||
* only looking for ioctl based extended permissions
|
||||
*/
|
||||
void services_compute_xperms_drivers(
|
||||
struct extended_perms *xperms,
|
||||
@@ -3548,38 +3548,38 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
||||
tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
|
||||
if (!tmprule)
|
||||
return -ENOMEM;
|
||||
|
||||
context_init(&tmprule->au_ctxt);
|
||||
|
||||
rcu_read_lock();
|
||||
policy = rcu_dereference(state->policy);
|
||||
policydb = &policy->policydb;
|
||||
|
||||
tmprule->au_seqno = policy->latest_granting;
|
||||
|
||||
switch (field) {
|
||||
case AUDIT_SUBJ_USER:
|
||||
case AUDIT_OBJ_USER:
|
||||
rc = -EINVAL;
|
||||
userdatum = symtab_search(&policydb->p_users, rulestr);
|
||||
if (!userdatum)
|
||||
goto out;
|
||||
if (!userdatum) {
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
tmprule->au_ctxt.user = userdatum->value;
|
||||
break;
|
||||
case AUDIT_SUBJ_ROLE:
|
||||
case AUDIT_OBJ_ROLE:
|
||||
rc = -EINVAL;
|
||||
roledatum = symtab_search(&policydb->p_roles, rulestr);
|
||||
if (!roledatum)
|
||||
goto out;
|
||||
if (!roledatum) {
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
tmprule->au_ctxt.role = roledatum->value;
|
||||
break;
|
||||
case AUDIT_SUBJ_TYPE:
|
||||
case AUDIT_OBJ_TYPE:
|
||||
rc = -EINVAL;
|
||||
typedatum = symtab_search(&policydb->p_types, rulestr);
|
||||
if (!typedatum)
|
||||
goto out;
|
||||
if (!typedatum) {
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
tmprule->au_ctxt.type = typedatum->value;
|
||||
break;
|
||||
case AUDIT_SUBJ_SEN:
|
||||
@@ -3589,20 +3589,18 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
||||
rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
|
||||
GFP_ATOMIC);
|
||||
if (rc)
|
||||
goto out;
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
rc = 0;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
if (rc) {
|
||||
selinux_audit_rule_free(tmprule);
|
||||
tmprule = NULL;
|
||||
}
|
||||
|
||||
*rule = tmprule;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
rcu_read_unlock();
|
||||
selinux_audit_rule_free(tmprule);
|
||||
*rule = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ struct inode_smack {
|
||||
struct task_smack {
|
||||
struct smack_known *smk_task; /* label for access control */
|
||||
struct smack_known *smk_forked; /* label when forked */
|
||||
struct smack_known *smk_transmuted;/* label when transmuted */
|
||||
struct list_head smk_rules; /* per task access rules */
|
||||
struct mutex smk_rules_lock; /* lock for the rules */
|
||||
struct list_head smk_relabel; /* transit allowed labels */
|
||||
|
||||
+47
-16
@@ -933,8 +933,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr, const char **name,
|
||||
void **value, size_t *len)
|
||||
{
|
||||
struct task_smack *tsp = smack_cred(current_cred());
|
||||
struct inode_smack *issp = smack_inode(inode);
|
||||
struct smack_known *skp = smk_of_current();
|
||||
struct smack_known *skp = smk_of_task(tsp);
|
||||
struct smack_known *isp = smk_of_inode(inode);
|
||||
struct smack_known *dsp = smk_of_inode(dir);
|
||||
int may;
|
||||
@@ -943,20 +944,34 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
*name = XATTR_SMACK_SUFFIX;
|
||||
|
||||
if (value && len) {
|
||||
rcu_read_lock();
|
||||
may = smk_access_entry(skp->smk_known, dsp->smk_known,
|
||||
&skp->smk_rules);
|
||||
rcu_read_unlock();
|
||||
/*
|
||||
* If equal, transmuting already occurred in
|
||||
* smack_dentry_create_files_as(). No need to check again.
|
||||
*/
|
||||
if (tsp->smk_task != tsp->smk_transmuted) {
|
||||
rcu_read_lock();
|
||||
may = smk_access_entry(skp->smk_known, dsp->smk_known,
|
||||
&skp->smk_rules);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* If the access rule allows transmutation and
|
||||
* the directory requests transmutation then
|
||||
* by all means transmute.
|
||||
* In addition to having smk_task equal to smk_transmuted,
|
||||
* if the access rule allows transmutation and the directory
|
||||
* requests transmutation then by all means transmute.
|
||||
* Mark the inode as changed.
|
||||
*/
|
||||
if (may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
|
||||
smk_inode_transmutable(dir)) {
|
||||
isp = dsp;
|
||||
if ((tsp->smk_task == tsp->smk_transmuted) ||
|
||||
(may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
|
||||
smk_inode_transmutable(dir))) {
|
||||
/*
|
||||
* The caller of smack_dentry_create_files_as()
|
||||
* should have overridden the current cred, so the
|
||||
* inode label was already set correctly in
|
||||
* smack_inode_alloc_security().
|
||||
*/
|
||||
if (tsp->smk_task != tsp->smk_transmuted)
|
||||
isp = dsp;
|
||||
issp->smk_flags |= SMK_INODE_CHANGED;
|
||||
}
|
||||
|
||||
@@ -1463,10 +1478,19 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
|
||||
struct super_block *sbp;
|
||||
struct inode *ip = inode;
|
||||
struct smack_known *isp;
|
||||
struct inode_smack *ispp;
|
||||
size_t label_len;
|
||||
char *label = NULL;
|
||||
|
||||
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0)
|
||||
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
|
||||
isp = smk_of_inode(inode);
|
||||
else {
|
||||
} else if (strcmp(name, XATTR_SMACK_TRANSMUTE) == 0) {
|
||||
ispp = smack_inode(inode);
|
||||
if (ispp->smk_flags & SMK_INODE_TRANSMUTE)
|
||||
label = TRANS_TRUE;
|
||||
else
|
||||
label = "";
|
||||
} else {
|
||||
/*
|
||||
* The rest of the Smack xattrs are only on sockets.
|
||||
*/
|
||||
@@ -1488,13 +1512,18 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!label)
|
||||
label = isp->smk_known;
|
||||
|
||||
label_len = strlen(label);
|
||||
|
||||
if (alloc) {
|
||||
*buffer = kstrdup(isp->smk_known, GFP_KERNEL);
|
||||
*buffer = kstrdup(label, GFP_KERNEL);
|
||||
if (*buffer == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return strlen(isp->smk_known);
|
||||
return label_len;
|
||||
}
|
||||
|
||||
|
||||
@@ -4753,8 +4782,10 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
|
||||
* providing access is transmuting use the containing
|
||||
* directory label instead of the process label.
|
||||
*/
|
||||
if (may > 0 && (may & MAY_TRANSMUTE))
|
||||
if (may > 0 && (may & MAY_TRANSMUTE)) {
|
||||
ntsp->smk_task = isp->smk_inode;
|
||||
ntsp->smk_transmuted = ntsp->smk_task;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_OVERLAY_FS=y
|
||||
CONFIG_SECURITY_LANDLOCK=y
|
||||
CONFIG_SECURITY_PATH=y
|
||||
CONFIG_PROC_FS=y
|
||||
CONFIG_SECURITY=y
|
||||
CONFIG_SECURITY_LANDLOCK=y
|
||||
CONFIG_SHMEM=y
|
||||
CONFIG_TMPFS_XATTR=y
|
||||
CONFIG_SYSFS=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_XATTR=y
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_HOSTFS=y
|
||||
@@ -10,6 +10,7 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <linux/landlock.h>
|
||||
#include <linux/magic.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -19,6 +20,7 @@
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -107,8 +109,10 @@ static bool fgrep(FILE *const inf, const char *const str)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool supports_overlayfs(void)
|
||||
static bool supports_filesystem(const char *const filesystem)
|
||||
{
|
||||
char str[32];
|
||||
int len;
|
||||
bool res;
|
||||
FILE *const inf = fopen("/proc/filesystems", "r");
|
||||
|
||||
@@ -119,11 +123,33 @@ static bool supports_overlayfs(void)
|
||||
if (!inf)
|
||||
return true;
|
||||
|
||||
res = fgrep(inf, "nodev\toverlay\n");
|
||||
/* filesystem can be null for bind mounts. */
|
||||
if (!filesystem)
|
||||
return true;
|
||||
|
||||
len = snprintf(str, sizeof(str), "nodev\t%s\n", filesystem);
|
||||
if (len >= sizeof(str))
|
||||
/* Ignores too-long filesystem names. */
|
||||
return true;
|
||||
|
||||
res = fgrep(inf, str);
|
||||
fclose(inf);
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool cwd_matches_fs(unsigned int fs_magic)
|
||||
{
|
||||
struct statfs statfs_buf;
|
||||
|
||||
if (!fs_magic)
|
||||
return true;
|
||||
|
||||
if (statfs(".", &statfs_buf))
|
||||
return true;
|
||||
|
||||
return statfs_buf.f_type == fs_magic;
|
||||
}
|
||||
|
||||
static void mkdir_parents(struct __test_metadata *const _metadata,
|
||||
const char *const path)
|
||||
{
|
||||
@@ -206,7 +232,26 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void prepare_layout(struct __test_metadata *const _metadata)
|
||||
struct mnt_opt {
|
||||
const char *const source;
|
||||
const char *const type;
|
||||
const unsigned long flags;
|
||||
const char *const data;
|
||||
};
|
||||
|
||||
const struct mnt_opt mnt_tmp = {
|
||||
.type = "tmpfs",
|
||||
.data = "size=4m,mode=700",
|
||||
};
|
||||
|
||||
static int mount_opt(const struct mnt_opt *const mnt, const char *const target)
|
||||
{
|
||||
return mount(mnt->source ?: mnt->type, target, mnt->type, mnt->flags,
|
||||
mnt->data);
|
||||
}
|
||||
|
||||
static void prepare_layout_opt(struct __test_metadata *const _metadata,
|
||||
const struct mnt_opt *const mnt)
|
||||
{
|
||||
disable_caps(_metadata);
|
||||
umask(0077);
|
||||
@@ -217,12 +262,28 @@ static void prepare_layout(struct __test_metadata *const _metadata)
|
||||
* for tests relying on pivot_root(2) and move_mount(2).
|
||||
*/
|
||||
set_cap(_metadata, CAP_SYS_ADMIN);
|
||||
ASSERT_EQ(0, unshare(CLONE_NEWNS));
|
||||
ASSERT_EQ(0, mount("tmp", TMP_DIR, "tmpfs", 0, "size=4m,mode=700"));
|
||||
ASSERT_EQ(0, unshare(CLONE_NEWNS | CLONE_NEWCGROUP));
|
||||
ASSERT_EQ(0, mount_opt(mnt, TMP_DIR))
|
||||
{
|
||||
TH_LOG("Failed to mount the %s filesystem: %s", mnt->type,
|
||||
strerror(errno));
|
||||
/*
|
||||
* FIXTURE_TEARDOWN() is not called when FIXTURE_SETUP()
|
||||
* failed, so we need to explicitly do a minimal cleanup to
|
||||
* avoid cascading errors with other tests that don't depend on
|
||||
* the same filesystem.
|
||||
*/
|
||||
remove_path(TMP_DIR);
|
||||
}
|
||||
ASSERT_EQ(0, mount(NULL, TMP_DIR, NULL, MS_PRIVATE | MS_REC, NULL));
|
||||
clear_cap(_metadata, CAP_SYS_ADMIN);
|
||||
}
|
||||
|
||||
static void prepare_layout(struct __test_metadata *const _metadata)
|
||||
{
|
||||
prepare_layout_opt(_metadata, &mnt_tmp);
|
||||
}
|
||||
|
||||
static void cleanup_layout(struct __test_metadata *const _metadata)
|
||||
{
|
||||
set_cap(_metadata, CAP_SYS_ADMIN);
|
||||
@@ -231,6 +292,20 @@ static void cleanup_layout(struct __test_metadata *const _metadata)
|
||||
EXPECT_EQ(0, remove_path(TMP_DIR));
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE(layout0) {};
|
||||
/* clang-format on */
|
||||
|
||||
FIXTURE_SETUP(layout0)
|
||||
{
|
||||
prepare_layout(_metadata);
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(layout0)
|
||||
{
|
||||
cleanup_layout(_metadata);
|
||||
}
|
||||
|
||||
static void create_layout1(struct __test_metadata *const _metadata)
|
||||
{
|
||||
create_file(_metadata, file1_s1d1);
|
||||
@@ -248,7 +323,7 @@ static void create_layout1(struct __test_metadata *const _metadata)
|
||||
create_file(_metadata, file1_s3d1);
|
||||
create_directory(_metadata, dir_s3d2);
|
||||
set_cap(_metadata, CAP_SYS_ADMIN);
|
||||
ASSERT_EQ(0, mount("tmp", dir_s3d2, "tmpfs", 0, "size=4m,mode=700"));
|
||||
ASSERT_EQ(0, mount_opt(&mnt_tmp, dir_s3d2));
|
||||
clear_cap(_metadata, CAP_SYS_ADMIN);
|
||||
|
||||
ASSERT_EQ(0, mkdir(dir_s3d3, 0700));
|
||||
@@ -262,11 +337,13 @@ static void remove_layout1(struct __test_metadata *const _metadata)
|
||||
EXPECT_EQ(0, remove_path(file1_s1d3));
|
||||
EXPECT_EQ(0, remove_path(file1_s1d2));
|
||||
EXPECT_EQ(0, remove_path(file1_s1d1));
|
||||
EXPECT_EQ(0, remove_path(dir_s1d3));
|
||||
|
||||
EXPECT_EQ(0, remove_path(file2_s2d3));
|
||||
EXPECT_EQ(0, remove_path(file1_s2d3));
|
||||
EXPECT_EQ(0, remove_path(file1_s2d2));
|
||||
EXPECT_EQ(0, remove_path(file1_s2d1));
|
||||
EXPECT_EQ(0, remove_path(dir_s2d2));
|
||||
|
||||
EXPECT_EQ(0, remove_path(file1_s3d1));
|
||||
EXPECT_EQ(0, remove_path(dir_s3d3));
|
||||
@@ -510,7 +587,7 @@ TEST_F_FORK(layout1, file_and_dir_access_rights)
|
||||
ASSERT_EQ(0, close(ruleset_fd));
|
||||
}
|
||||
|
||||
TEST_F_FORK(layout1, unknown_access_rights)
|
||||
TEST_F_FORK(layout0, unknown_access_rights)
|
||||
{
|
||||
__u64 access_mask;
|
||||
|
||||
@@ -608,7 +685,7 @@ static void enforce_ruleset(struct __test_metadata *const _metadata,
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F_FORK(layout1, proc_nsfs)
|
||||
TEST_F_FORK(layout0, proc_nsfs)
|
||||
{
|
||||
const struct rule rules[] = {
|
||||
{
|
||||
@@ -657,11 +734,11 @@ TEST_F_FORK(layout1, proc_nsfs)
|
||||
ASSERT_EQ(0, close(path_beneath.parent_fd));
|
||||
}
|
||||
|
||||
TEST_F_FORK(layout1, unpriv)
|
||||
TEST_F_FORK(layout0, unpriv)
|
||||
{
|
||||
const struct rule rules[] = {
|
||||
{
|
||||
.path = dir_s1d2,
|
||||
.path = TMP_DIR,
|
||||
.access = ACCESS_RO,
|
||||
},
|
||||
{},
|
||||
@@ -1301,12 +1378,12 @@ TEST_F_FORK(layout1, inherit_superset)
|
||||
ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
|
||||
}
|
||||
|
||||
TEST_F_FORK(layout1, max_layers)
|
||||
TEST_F_FORK(layout0, max_layers)
|
||||
{
|
||||
int i, err;
|
||||
const struct rule rules[] = {
|
||||
{
|
||||
.path = dir_s1d2,
|
||||
.path = TMP_DIR,
|
||||
.access = ACCESS_RO,
|
||||
},
|
||||
{},
|
||||
@@ -4030,21 +4107,24 @@ static const char (*merge_sub_files[])[] = {
|
||||
* └── work
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE(layout2_overlay) {};
|
||||
/* clang-format on */
|
||||
FIXTURE(layout2_overlay)
|
||||
{
|
||||
bool skip_test;
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(layout2_overlay)
|
||||
{
|
||||
if (!supports_overlayfs())
|
||||
SKIP(return, "overlayfs is not supported");
|
||||
if (!supports_filesystem("overlay")) {
|
||||
self->skip_test = true;
|
||||
SKIP(return, "overlayfs is not supported (setup)");
|
||||
}
|
||||
|
||||
prepare_layout(_metadata);
|
||||
|
||||
create_directory(_metadata, LOWER_BASE);
|
||||
set_cap(_metadata, CAP_SYS_ADMIN);
|
||||
/* Creates tmpfs mount points to get deterministic overlayfs. */
|
||||
ASSERT_EQ(0, mount("tmp", LOWER_BASE, "tmpfs", 0, "size=4m,mode=700"));
|
||||
ASSERT_EQ(0, mount_opt(&mnt_tmp, LOWER_BASE));
|
||||
clear_cap(_metadata, CAP_SYS_ADMIN);
|
||||
create_file(_metadata, lower_fl1);
|
||||
create_file(_metadata, lower_dl1_fl2);
|
||||
@@ -4054,7 +4134,7 @@ FIXTURE_SETUP(layout2_overlay)
|
||||
|
||||
create_directory(_metadata, UPPER_BASE);
|
||||
set_cap(_metadata, CAP_SYS_ADMIN);
|
||||
ASSERT_EQ(0, mount("tmp", UPPER_BASE, "tmpfs", 0, "size=4m,mode=700"));
|
||||
ASSERT_EQ(0, mount_opt(&mnt_tmp, UPPER_BASE));
|
||||
clear_cap(_metadata, CAP_SYS_ADMIN);
|
||||
create_file(_metadata, upper_fu1);
|
||||
create_file(_metadata, upper_du1_fu2);
|
||||
@@ -4075,8 +4155,8 @@ FIXTURE_SETUP(layout2_overlay)
|
||||
|
||||
FIXTURE_TEARDOWN(layout2_overlay)
|
||||
{
|
||||
if (!supports_overlayfs())
|
||||
SKIP(return, "overlayfs is not supported");
|
||||
if (self->skip_test)
|
||||
SKIP(return, "overlayfs is not supported (teardown)");
|
||||
|
||||
EXPECT_EQ(0, remove_path(lower_do1_fl3));
|
||||
EXPECT_EQ(0, remove_path(lower_dl1_fl2));
|
||||
@@ -4109,8 +4189,8 @@ FIXTURE_TEARDOWN(layout2_overlay)
|
||||
|
||||
TEST_F_FORK(layout2_overlay, no_restriction)
|
||||
{
|
||||
if (!supports_overlayfs())
|
||||
SKIP(return, "overlayfs is not supported");
|
||||
if (self->skip_test)
|
||||
SKIP(return, "overlayfs is not supported (test)");
|
||||
|
||||
ASSERT_EQ(0, test_open(lower_fl1, O_RDONLY));
|
||||
ASSERT_EQ(0, test_open(lower_dl1, O_RDONLY));
|
||||
@@ -4275,8 +4355,8 @@ TEST_F_FORK(layout2_overlay, same_content_different_file)
|
||||
size_t i;
|
||||
const char *path_entry;
|
||||
|
||||
if (!supports_overlayfs())
|
||||
SKIP(return, "overlayfs is not supported");
|
||||
if (self->skip_test)
|
||||
SKIP(return, "overlayfs is not supported (test)");
|
||||
|
||||
/* Sets rules on base directories (i.e. outside overlay scope). */
|
||||
ruleset_fd = create_ruleset(_metadata, ACCESS_RW, layer1_base);
|
||||
@@ -4423,4 +4503,261 @@ TEST_F_FORK(layout2_overlay, same_content_different_file)
|
||||
}
|
||||
}
|
||||
|
||||
FIXTURE(layout3_fs)
|
||||
{
|
||||
bool has_created_dir;
|
||||
bool has_created_file;
|
||||
char *dir_path;
|
||||
bool skip_test;
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT(layout3_fs)
|
||||
{
|
||||
const struct mnt_opt mnt;
|
||||
const char *const file_path;
|
||||
unsigned int cwd_fs_magic;
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE_VARIANT_ADD(layout3_fs, tmpfs) {
|
||||
/* clang-format on */
|
||||
.mnt = mnt_tmp,
|
||||
.file_path = file1_s1d1,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(layout3_fs, ramfs) {
|
||||
.mnt = {
|
||||
.type = "ramfs",
|
||||
.data = "mode=700",
|
||||
},
|
||||
.file_path = TMP_DIR "/dir/file",
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(layout3_fs, cgroup2) {
|
||||
.mnt = {
|
||||
.type = "cgroup2",
|
||||
},
|
||||
.file_path = TMP_DIR "/test/cgroup.procs",
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(layout3_fs, proc) {
|
||||
.mnt = {
|
||||
.type = "proc",
|
||||
},
|
||||
.file_path = TMP_DIR "/self/status",
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(layout3_fs, sysfs) {
|
||||
.mnt = {
|
||||
.type = "sysfs",
|
||||
},
|
||||
.file_path = TMP_DIR "/kernel/notes",
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(layout3_fs, hostfs) {
|
||||
.mnt = {
|
||||
.source = TMP_DIR,
|
||||
.flags = MS_BIND,
|
||||
},
|
||||
.file_path = TMP_DIR "/dir/file",
|
||||
.cwd_fs_magic = HOSTFS_SUPER_MAGIC,
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(layout3_fs)
|
||||
{
|
||||
struct stat statbuf;
|
||||
const char *slash;
|
||||
size_t dir_len;
|
||||
|
||||
if (!supports_filesystem(variant->mnt.type) ||
|
||||
!cwd_matches_fs(variant->cwd_fs_magic)) {
|
||||
self->skip_test = true;
|
||||
SKIP(return, "this filesystem is not supported (setup)");
|
||||
}
|
||||
|
||||
slash = strrchr(variant->file_path, '/');
|
||||
ASSERT_NE(slash, NULL);
|
||||
dir_len = (size_t)slash - (size_t)variant->file_path;
|
||||
ASSERT_LT(0, dir_len);
|
||||
self->dir_path = malloc(dir_len + 1);
|
||||
self->dir_path[dir_len] = '\0';
|
||||
strncpy(self->dir_path, variant->file_path, dir_len);
|
||||
|
||||
prepare_layout_opt(_metadata, &variant->mnt);
|
||||
|
||||
/* Creates directory when required. */
|
||||
if (stat(self->dir_path, &statbuf)) {
|
||||
set_cap(_metadata, CAP_DAC_OVERRIDE);
|
||||
EXPECT_EQ(0, mkdir(self->dir_path, 0700))
|
||||
{
|
||||
TH_LOG("Failed to create directory \"%s\": %s",
|
||||
self->dir_path, strerror(errno));
|
||||
free(self->dir_path);
|
||||
self->dir_path = NULL;
|
||||
}
|
||||
self->has_created_dir = true;
|
||||
clear_cap(_metadata, CAP_DAC_OVERRIDE);
|
||||
}
|
||||
|
||||
/* Creates file when required. */
|
||||
if (stat(variant->file_path, &statbuf)) {
|
||||
int fd;
|
||||
|
||||
set_cap(_metadata, CAP_DAC_OVERRIDE);
|
||||
fd = creat(variant->file_path, 0600);
|
||||
EXPECT_LE(0, fd)
|
||||
{
|
||||
TH_LOG("Failed to create file \"%s\": %s",
|
||||
variant->file_path, strerror(errno));
|
||||
}
|
||||
EXPECT_EQ(0, close(fd));
|
||||
self->has_created_file = true;
|
||||
clear_cap(_metadata, CAP_DAC_OVERRIDE);
|
||||
}
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(layout3_fs)
|
||||
{
|
||||
if (self->skip_test)
|
||||
SKIP(return, "this filesystem is not supported (teardown)");
|
||||
|
||||
if (self->has_created_file) {
|
||||
set_cap(_metadata, CAP_DAC_OVERRIDE);
|
||||
/*
|
||||
* Don't check for error because the file might already
|
||||
* have been removed (cf. release_inode test).
|
||||
*/
|
||||
unlink(variant->file_path);
|
||||
clear_cap(_metadata, CAP_DAC_OVERRIDE);
|
||||
}
|
||||
|
||||
if (self->has_created_dir) {
|
||||
set_cap(_metadata, CAP_DAC_OVERRIDE);
|
||||
/*
|
||||
* Don't check for error because the directory might already
|
||||
* have been removed (cf. release_inode test).
|
||||
*/
|
||||
rmdir(self->dir_path);
|
||||
clear_cap(_metadata, CAP_DAC_OVERRIDE);
|
||||
}
|
||||
free(self->dir_path);
|
||||
self->dir_path = NULL;
|
||||
|
||||
cleanup_layout(_metadata);
|
||||
}
|
||||
|
||||
static void layer3_fs_tag_inode(struct __test_metadata *const _metadata,
|
||||
FIXTURE_DATA(layout3_fs) * self,
|
||||
const FIXTURE_VARIANT(layout3_fs) * variant,
|
||||
const char *const rule_path)
|
||||
{
|
||||
const struct rule layer1_allow_read_file[] = {
|
||||
{
|
||||
.path = rule_path,
|
||||
.access = LANDLOCK_ACCESS_FS_READ_FILE,
|
||||
},
|
||||
{},
|
||||
};
|
||||
const struct landlock_ruleset_attr layer2_deny_everything_attr = {
|
||||
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
|
||||
};
|
||||
const char *const dev_null_path = "/dev/null";
|
||||
int ruleset_fd;
|
||||
|
||||
if (self->skip_test)
|
||||
SKIP(return, "this filesystem is not supported (test)");
|
||||
|
||||
/* Checks without Landlock. */
|
||||
EXPECT_EQ(0, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
|
||||
EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
|
||||
|
||||
ruleset_fd = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE,
|
||||
layer1_allow_read_file);
|
||||
EXPECT_LE(0, ruleset_fd);
|
||||
enforce_ruleset(_metadata, ruleset_fd);
|
||||
EXPECT_EQ(0, close(ruleset_fd));
|
||||
|
||||
EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
|
||||
EXPECT_EQ(0, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
|
||||
|
||||
/* Forbids directory reading. */
|
||||
ruleset_fd =
|
||||
landlock_create_ruleset(&layer2_deny_everything_attr,
|
||||
sizeof(layer2_deny_everything_attr), 0);
|
||||
EXPECT_LE(0, ruleset_fd);
|
||||
enforce_ruleset(_metadata, ruleset_fd);
|
||||
EXPECT_EQ(0, close(ruleset_fd));
|
||||
|
||||
/* Checks with Landlock and forbidden access. */
|
||||
EXPECT_EQ(EACCES, test_open(dev_null_path, O_RDONLY | O_CLOEXEC));
|
||||
EXPECT_EQ(EACCES, test_open(variant->file_path, O_RDONLY | O_CLOEXEC));
|
||||
}
|
||||
|
||||
/* Matrix of tests to check file hierarchy evaluation. */
|
||||
|
||||
TEST_F_FORK(layout3_fs, tag_inode_dir_parent)
|
||||
{
|
||||
/* The current directory must not be the root for this test. */
|
||||
layer3_fs_tag_inode(_metadata, self, variant, ".");
|
||||
}
|
||||
|
||||
TEST_F_FORK(layout3_fs, tag_inode_dir_mnt)
|
||||
{
|
||||
layer3_fs_tag_inode(_metadata, self, variant, TMP_DIR);
|
||||
}
|
||||
|
||||
TEST_F_FORK(layout3_fs, tag_inode_dir_child)
|
||||
{
|
||||
layer3_fs_tag_inode(_metadata, self, variant, self->dir_path);
|
||||
}
|
||||
|
||||
TEST_F_FORK(layout3_fs, tag_inode_file)
|
||||
{
|
||||
layer3_fs_tag_inode(_metadata, self, variant, variant->file_path);
|
||||
}
|
||||
|
||||
/* Light version of layout1.release_inodes */
|
||||
TEST_F_FORK(layout3_fs, release_inodes)
|
||||
{
|
||||
const struct rule layer1[] = {
|
||||
{
|
||||
.path = TMP_DIR,
|
||||
.access = LANDLOCK_ACCESS_FS_READ_DIR,
|
||||
},
|
||||
{},
|
||||
};
|
||||
int ruleset_fd;
|
||||
|
||||
if (self->skip_test)
|
||||
SKIP(return, "this filesystem is not supported (test)");
|
||||
|
||||
/* Clean up for the teardown to not fail. */
|
||||
if (self->has_created_file)
|
||||
EXPECT_EQ(0, remove_path(variant->file_path));
|
||||
|
||||
if (self->has_created_dir)
|
||||
/* Don't check for error because of cgroup specificities. */
|
||||
remove_path(self->dir_path);
|
||||
|
||||
ruleset_fd =
|
||||
create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_DIR, layer1);
|
||||
ASSERT_LE(0, ruleset_fd);
|
||||
|
||||
/* Unmount the filesystem while it is being used by a ruleset. */
|
||||
set_cap(_metadata, CAP_SYS_ADMIN);
|
||||
ASSERT_EQ(0, umount(TMP_DIR));
|
||||
clear_cap(_metadata, CAP_SYS_ADMIN);
|
||||
|
||||
/* Replaces with a new mount point to simplify FIXTURE_TEARDOWN. */
|
||||
set_cap(_metadata, CAP_SYS_ADMIN);
|
||||
ASSERT_EQ(0, mount_opt(&mnt_tmp, TMP_DIR));
|
||||
clear_cap(_metadata, CAP_SYS_ADMIN);
|
||||
|
||||
enforce_ruleset(_metadata, ruleset_fd);
|
||||
ASSERT_EQ(0, close(ruleset_fd));
|
||||
|
||||
/* Checks that access to the new mount point is denied. */
|
||||
ASSERT_EQ(EACCES, test_open(TMP_DIR, O_RDONLY));
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
|
||||
Reference in New Issue
Block a user