Merge f359287765 ("Merge branch 'from-miklos' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs") into android-mainline

Baby steps on the way to 5.8-rc1

Change-Id: I2b608853beaeaeecbc24bcd32386aca21666cc13
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman 2020-06-12 14:27:02 +02:00
commit 6663438904
51 changed files with 530 additions and 419 deletions

View File

@ -477,3 +477,4 @@
# 545 reserved for clone3
547 common openat2 sys_openat2
548 common pidfd_getfd sys_pidfd_getfd
549 common faccessat2 sys_faccessat2

View File

@ -451,3 +451,4 @@
435 common clone3 sys_clone3
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -38,7 +38,7 @@
#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)
#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)
#define __NR_compat_syscalls 439
#define __NR_compat_syscalls 440
#endif
#define __ARCH_WANT_SYS_CLONE

View File

@ -883,6 +883,8 @@ __SYSCALL(__NR_clone3, sys_clone3)
__SYSCALL(__NR_openat2, sys_openat2)
#define __NR_pidfd_getfd 438
__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
#define __NR_faccessat2 439
__SYSCALL(__NR_faccessat2, sys_faccessat2)
/*
* Please add new compat syscalls above this comment and update

View File

@ -358,3 +358,4 @@
# 435 reserved for clone3
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -437,3 +437,4 @@
435 common clone3 __sys_clone3
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -443,3 +443,4 @@
435 common clone3 sys_clone3
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -376,3 +376,4 @@
435 n32 clone3 __sys_clone3
437 n32 openat2 sys_openat2
438 n32 pidfd_getfd sys_pidfd_getfd
439 n32 faccessat2 sys_faccessat2

View File

@ -352,3 +352,4 @@
435 n64 clone3 __sys_clone3
437 n64 openat2 sys_openat2
438 n64 pidfd_getfd sys_pidfd_getfd
439 n64 faccessat2 sys_faccessat2

View File

@ -425,3 +425,4 @@
435 o32 clone3 __sys_clone3
437 o32 openat2 sys_openat2
438 o32 pidfd_getfd sys_pidfd_getfd
439 o32 faccessat2 sys_faccessat2

View File

@ -435,3 +435,4 @@
435 common clone3 sys_clone3_wrapper
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -527,3 +527,4 @@
435 spu clone3 sys_ni_syscall
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -21,22 +21,6 @@
#include "spufs.h"
static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer,
size_t size, loff_t *off)
{
u64 data;
int ret;
if (spufs_coredump_read[num].read)
return spufs_coredump_read[num].read(ctx, buffer, size, off);
data = spufs_coredump_read[num].get(ctx);
ret = snprintf(buffer, size, "0x%.16llx", data);
if (ret >= size)
return size;
return ++ret; /* count trailing NULL */
}
static int spufs_ctx_note_size(struct spu_context *ctx, int dfd)
{
int i, sz, total = 0;
@ -118,58 +102,43 @@ int spufs_coredump_extra_notes_size(void)
static int spufs_arch_write_note(struct spu_context *ctx, int i,
struct coredump_params *cprm, int dfd)
{
loff_t pos = 0;
int sz, rc, total = 0;
const int bufsz = PAGE_SIZE;
char *name;
char fullname[80], *buf;
size_t sz = spufs_coredump_read[i].size;
char fullname[80];
struct elf_note en;
size_t skip;
size_t ret;
buf = (void *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
name = spufs_coredump_read[i].name;
sz = spufs_coredump_read[i].size;
sprintf(fullname, "SPU/%d/%s", dfd, name);
sprintf(fullname, "SPU/%d/%s", dfd, spufs_coredump_read[i].name);
en.n_namesz = strlen(fullname) + 1;
en.n_descsz = sz;
en.n_type = NT_SPU;
if (!dump_emit(cprm, &en, sizeof(en)))
goto Eio;
return -EIO;
if (!dump_emit(cprm, fullname, en.n_namesz))
goto Eio;
return -EIO;
if (!dump_align(cprm, 4))
goto Eio;
return -EIO;
do {
rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
if (rc > 0) {
if (!dump_emit(cprm, buf, rc))
goto Eio;
total += rc;
}
} while (rc == bufsz && total < sz);
if (spufs_coredump_read[i].dump) {
ret = spufs_coredump_read[i].dump(ctx, cprm);
if (ret < 0)
return ret;
} else {
char buf[32];
if (rc < 0)
goto out;
ret = snprintf(buf, sizeof(buf), "0x%.16llx",
spufs_coredump_read[i].get(ctx));
if (ret >= sizeof(buf))
return sizeof(buf);
skip = roundup(cprm->pos - total + sz, 4) - cprm->pos;
if (!dump_skip(cprm, skip))
goto Eio;
/* count trailing the NULL: */
if (!dump_emit(cprm, buf, ret + 1))
return -EIO;
}
rc = 0;
out:
free_page((unsigned long)buf);
return rc;
Eio:
free_page((unsigned long)buf);
return -EIO;
if (!dump_skip(cprm, roundup(cprm->pos - ret + sz, 4) - cprm->pos))
return -EIO;
return 0;
}
int spufs_coredump_extra_notes_write(struct coredump_params *cprm)

View File

@ -9,6 +9,7 @@
#undef DEBUG
#include <linux/coredump.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/export.h>
@ -129,6 +130,14 @@ static ssize_t spufs_attr_write(struct file *file, const char __user *buf,
return ret;
}
static ssize_t spufs_dump_emit(struct coredump_params *cprm, void *buf,
size_t size)
{
if (!dump_emit(cprm, buf, size))
return -EIO;
return size;
}
#define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
static int __fops ## _open(struct inode *inode, struct file *file) \
{ \
@ -172,12 +181,9 @@ spufs_mem_release(struct inode *inode, struct file *file)
}
static ssize_t
__spufs_mem_read(struct spu_context *ctx, char __user *buffer,
size_t size, loff_t *pos)
spufs_mem_dump(struct spu_context *ctx, struct coredump_params *cprm)
{
char *local_store = ctx->ops->get_ls(ctx);
return simple_read_from_buffer(buffer, size, pos, local_store,
LS_SIZE);
return spufs_dump_emit(cprm, ctx->ops->get_ls(ctx), LS_SIZE);
}
static ssize_t
@ -190,7 +196,8 @@ spufs_mem_read(struct file *file, char __user *buffer,
ret = spu_acquire(ctx);
if (ret)
return ret;
ret = __spufs_mem_read(ctx, buffer, size, pos);
ret = simple_read_from_buffer(buffer, size, pos, ctx->ops->get_ls(ctx),
LS_SIZE);
spu_release(ctx);
return ret;
@ -459,12 +466,10 @@ spufs_regs_open(struct inode *inode, struct file *file)
}
static ssize_t
__spufs_regs_read(struct spu_context *ctx, char __user *buffer,
size_t size, loff_t *pos)
spufs_regs_dump(struct spu_context *ctx, struct coredump_params *cprm)
{
struct spu_lscsa *lscsa = ctx->csa.lscsa;
return simple_read_from_buffer(buffer, size, pos,
lscsa->gprs, sizeof lscsa->gprs);
return spufs_dump_emit(cprm, ctx->csa.lscsa->gprs,
sizeof(ctx->csa.lscsa->gprs));
}
static ssize_t
@ -482,7 +487,8 @@ spufs_regs_read(struct file *file, char __user *buffer,
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
ret = __spufs_regs_read(ctx, buffer, size, pos);
ret = simple_read_from_buffer(buffer, size, pos, ctx->csa.lscsa->gprs,
sizeof(ctx->csa.lscsa->gprs));
spu_release_saved(ctx);
return ret;
}
@ -517,12 +523,10 @@ static const struct file_operations spufs_regs_fops = {
};
static ssize_t
__spufs_fpcr_read(struct spu_context *ctx, char __user * buffer,
size_t size, loff_t * pos)
spufs_fpcr_dump(struct spu_context *ctx, struct coredump_params *cprm)
{
struct spu_lscsa *lscsa = ctx->csa.lscsa;
return simple_read_from_buffer(buffer, size, pos,
&lscsa->fpcr, sizeof(lscsa->fpcr));
return spufs_dump_emit(cprm, &ctx->csa.lscsa->fpcr,
sizeof(ctx->csa.lscsa->fpcr));
}
static ssize_t
@ -535,7 +539,8 @@ spufs_fpcr_read(struct file *file, char __user * buffer,
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
ret = __spufs_fpcr_read(ctx, buffer, size, pos);
ret = simple_read_from_buffer(buffer, size, pos, &ctx->csa.lscsa->fpcr,
sizeof(ctx->csa.lscsa->fpcr));
spu_release_saved(ctx);
return ret;
}
@ -590,17 +595,12 @@ static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
u32 mbox_data, __user *udata;
u32 mbox_data, __user *udata = (void __user *)buf;
ssize_t count;
if (len < 4)
return -EINVAL;
if (!access_ok(buf, len))
return -EFAULT;
udata = (void __user *)buf;
count = spu_acquire(ctx);
if (count)
return count;
@ -616,7 +616,7 @@ static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
* but still need to return the data we have
* read successfully so far.
*/
ret = __put_user(mbox_data, udata);
ret = put_user(mbox_data, udata);
if (ret) {
if (!count)
count = -EFAULT;
@ -698,17 +698,12 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
u32 ibox_data, __user *udata;
u32 ibox_data, __user *udata = (void __user *)buf;
ssize_t count;
if (len < 4)
return -EINVAL;
if (!access_ok(buf, len))
return -EFAULT;
udata = (void __user *)buf;
count = spu_acquire(ctx);
if (count)
goto out;
@ -727,7 +722,7 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
}
/* if we can't write at all, return -EFAULT */
count = __put_user(ibox_data, udata);
count = put_user(ibox_data, udata);
if (count)
goto out_unlock;
@ -741,7 +736,7 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
* but still need to return the data we have
* read successfully so far.
*/
ret = __put_user(ibox_data, udata);
ret = put_user(ibox_data, udata);
if (ret)
break;
}
@ -836,17 +831,13 @@ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
u32 wbox_data, __user *udata;
u32 wbox_data, __user *udata = (void __user *)buf;
ssize_t count;
if (len < 4)
return -EINVAL;
udata = (void __user *)buf;
if (!access_ok(buf, len))
return -EFAULT;
if (__get_user(wbox_data, udata))
if (get_user(wbox_data, udata))
return -EFAULT;
count = spu_acquire(ctx);
@ -873,7 +864,7 @@ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
/* write as much as possible */
for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
int ret;
ret = __get_user(wbox_data, udata);
ret = get_user(wbox_data, udata);
if (ret)
break;
@ -967,28 +958,26 @@ spufs_signal1_release(struct inode *inode, struct file *file)
return 0;
}
static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
size_t len, loff_t *pos)
static ssize_t spufs_signal1_dump(struct spu_context *ctx,
struct coredump_params *cprm)
{
int ret = 0;
u32 data;
if (!ctx->csa.spu_chnlcnt_RW[3])
return 0;
return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[3],
sizeof(ctx->csa.spu_chnldata_RW[3]));
}
if (len < 4)
static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
size_t len)
{
if (len < sizeof(ctx->csa.spu_chnldata_RW[3]))
return -EINVAL;
if (ctx->csa.spu_chnlcnt_RW[3]) {
data = ctx->csa.spu_chnldata_RW[3];
ret = 4;
}
if (!ret)
goto out;
if (copy_to_user(buf, &data, 4))
if (!ctx->csa.spu_chnlcnt_RW[3])
return 0;
if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[3],
sizeof(ctx->csa.spu_chnldata_RW[3])))
return -EFAULT;
out:
return ret;
return sizeof(ctx->csa.spu_chnldata_RW[3]);
}
static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
@ -1000,7 +989,7 @@ static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
ret = __spufs_signal1_read(ctx, buf, len, pos);
ret = __spufs_signal1_read(ctx, buf, len);
spu_release_saved(ctx);
return ret;
@ -1104,28 +1093,26 @@ spufs_signal2_release(struct inode *inode, struct file *file)
return 0;
}
static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
size_t len, loff_t *pos)
static ssize_t spufs_signal2_dump(struct spu_context *ctx,
struct coredump_params *cprm)
{
int ret = 0;
u32 data;
if (!ctx->csa.spu_chnlcnt_RW[4])
return 0;
return spufs_dump_emit(cprm, &ctx->csa.spu_chnldata_RW[4],
sizeof(ctx->csa.spu_chnldata_RW[4]));
}
if (len < 4)
static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
size_t len)
{
if (len < sizeof(ctx->csa.spu_chnldata_RW[4]))
return -EINVAL;
if (ctx->csa.spu_chnlcnt_RW[4]) {
data = ctx->csa.spu_chnldata_RW[4];
ret = 4;
}
if (!ret)
goto out;
if (copy_to_user(buf, &data, 4))
if (!ctx->csa.spu_chnlcnt_RW[4])
return 0;
if (copy_to_user(buf, &ctx->csa.spu_chnldata_RW[4],
sizeof(ctx->csa.spu_chnldata_RW[4])))
return -EFAULT;
out:
return ret;
return sizeof(ctx->csa.spu_chnldata_RW[4]);
}
static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
@ -1137,7 +1124,7 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
ret = __spufs_signal2_read(ctx, buf, len, pos);
ret = __spufs_signal2_read(ctx, buf, len);
spu_release_saved(ctx);
return ret;
@ -1961,38 +1948,36 @@ static const struct file_operations spufs_caps_fops = {
.release = single_release,
};
static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
char __user *buf, size_t len, loff_t *pos)
static ssize_t spufs_mbox_info_dump(struct spu_context *ctx,
struct coredump_params *cprm)
{
u32 data;
/* EOF if there's no entry in the mbox */
if (!(ctx->csa.prob.mb_stat_R & 0x0000ff))
return 0;
data = ctx->csa.prob.pu_mb_R;
return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
return spufs_dump_emit(cprm, &ctx->csa.prob.pu_mb_R,
sizeof(ctx->csa.prob.pu_mb_R));
}
static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
int ret;
struct spu_context *ctx = file->private_data;
if (!access_ok(buf, len))
return -EFAULT;
u32 stat, data;
int ret;
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
spin_lock(&ctx->csa.register_lock);
ret = __spufs_mbox_info_read(ctx, buf, len, pos);
stat = ctx->csa.prob.mb_stat_R;
data = ctx->csa.prob.pu_mb_R;
spin_unlock(&ctx->csa.register_lock);
spu_release_saved(ctx);
return ret;
/* EOF if there's no entry in the mbox */
if (!(stat & 0x0000ff))
return 0;
return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
}
static const struct file_operations spufs_mbox_info_fops = {
@ -2001,38 +1986,36 @@ static const struct file_operations spufs_mbox_info_fops = {
.llseek = generic_file_llseek,
};
static ssize_t __spufs_ibox_info_read(struct spu_context *ctx,
char __user *buf, size_t len, loff_t *pos)
static ssize_t spufs_ibox_info_dump(struct spu_context *ctx,
struct coredump_params *cprm)
{
u32 data;
/* EOF if there's no entry in the ibox */
if (!(ctx->csa.prob.mb_stat_R & 0xff0000))
return 0;
data = ctx->csa.priv2.puint_mb_R;
return simple_read_from_buffer(buf, len, pos, &data, sizeof data);
return spufs_dump_emit(cprm, &ctx->csa.priv2.puint_mb_R,
sizeof(ctx->csa.priv2.puint_mb_R));
}
static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
u32 stat, data;
int ret;
if (!access_ok(buf, len))
return -EFAULT;
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
spin_lock(&ctx->csa.register_lock);
ret = __spufs_ibox_info_read(ctx, buf, len, pos);
stat = ctx->csa.prob.mb_stat_R;
data = ctx->csa.priv2.puint_mb_R;
spin_unlock(&ctx->csa.register_lock);
spu_release_saved(ctx);
return ret;
/* EOF if there's no entry in the ibox */
if (!(stat & 0xff0000))
return 0;
return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
}
static const struct file_operations spufs_ibox_info_fops = {
@ -2041,41 +2024,36 @@ static const struct file_operations spufs_ibox_info_fops = {
.llseek = generic_file_llseek,
};
static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
char __user *buf, size_t len, loff_t *pos)
static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
{
int i, cnt;
u32 data[4];
u32 wbox_stat;
return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
}
wbox_stat = ctx->csa.prob.mb_stat_R;
cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
for (i = 0; i < cnt; i++) {
data[i] = ctx->csa.spu_mailbox_data[i];
}
return simple_read_from_buffer(buf, len, pos, &data,
cnt * sizeof(u32));
static ssize_t spufs_wbox_info_dump(struct spu_context *ctx,
struct coredump_params *cprm)
{
return spufs_dump_emit(cprm, &ctx->csa.spu_mailbox_data,
spufs_wbox_info_cnt(ctx));
}
static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
int ret;
if (!access_ok(buf, len))
return -EFAULT;
u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
int ret, count;
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
spin_lock(&ctx->csa.register_lock);
ret = __spufs_wbox_info_read(ctx, buf, len, pos);
count = spufs_wbox_info_cnt(ctx);
memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
spin_unlock(&ctx->csa.register_lock);
spu_release_saved(ctx);
return ret;
return simple_read_from_buffer(buf, len, pos, &data,
count * sizeof(u32));
}
static const struct file_operations spufs_wbox_info_fops = {
@ -2084,50 +2062,53 @@ static const struct file_operations spufs_wbox_info_fops = {
.llseek = generic_file_llseek,
};
static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
char __user *buf, size_t len, loff_t *pos)
static void spufs_get_dma_info(struct spu_context *ctx,
struct spu_dma_info *info)
{
struct spu_dma_info info;
struct mfc_cq_sr *qp, *spuqp;
int i;
info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
for (i = 0; i < 16; i++) {
qp = &info.dma_info_command_data[i];
spuqp = &ctx->csa.priv2.spuq[i];
struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
}
}
return simple_read_from_buffer(buf, len, pos, &info,
sizeof info);
static ssize_t spufs_dma_info_dump(struct spu_context *ctx,
struct coredump_params *cprm)
{
struct spu_dma_info info;
spufs_get_dma_info(ctx, &info);
return spufs_dump_emit(cprm, &info, sizeof(info));
}
static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
struct spu_dma_info info;
int ret;
if (!access_ok(buf, len))
return -EFAULT;
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
spin_lock(&ctx->csa.register_lock);
ret = __spufs_dma_info_read(ctx, buf, len, pos);
spufs_get_dma_info(ctx, &info);
spin_unlock(&ctx->csa.register_lock);
spu_release_saved(ctx);
return ret;
return simple_read_from_buffer(buf, len, pos, &info,
sizeof(info));
}
static const struct file_operations spufs_dma_info_fops = {
@ -2136,52 +2117,55 @@ static const struct file_operations spufs_dma_info_fops = {
.llseek = no_llseek,
};
static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
char __user *buf, size_t len, loff_t *pos)
static void spufs_get_proxydma_info(struct spu_context *ctx,
struct spu_proxydma_info *info)
{
struct spu_proxydma_info info;
struct mfc_cq_sr *qp, *puqp;
int ret = sizeof info;
int i;
if (len < ret)
return -EINVAL;
info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
if (!access_ok(buf, len))
return -EFAULT;
info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
for (i = 0; i < 8; i++) {
qp = &info.proxydma_info_command_data[i];
puqp = &ctx->csa.priv2.puq[i];
struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
}
}
return simple_read_from_buffer(buf, len, pos, &info,
sizeof info);
static ssize_t spufs_proxydma_info_dump(struct spu_context *ctx,
struct coredump_params *cprm)
{
struct spu_proxydma_info info;
spufs_get_proxydma_info(ctx, &info);
return spufs_dump_emit(cprm, &info, sizeof(info));
}
static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
struct spu_proxydma_info info;
int ret;
if (len < sizeof(info))
return -EINVAL;
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
spin_lock(&ctx->csa.register_lock);
ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
spufs_get_proxydma_info(ctx, &info);
spin_unlock(&ctx->csa.register_lock);
spu_release_saved(ctx);
return ret;
return simple_read_from_buffer(buf, len, pos, &info,
sizeof(info));
}
static const struct file_operations spufs_proxydma_info_fops = {
@ -2625,23 +2609,23 @@ const struct spufs_tree_descr spufs_dir_debug_contents[] = {
};
const struct spufs_coredump_reader spufs_coredump_read[] = {
{ "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])},
{ "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) },
{ "regs", spufs_regs_dump, NULL, sizeof(struct spu_reg128[128])},
{ "fpcr", spufs_fpcr_dump, NULL, sizeof(struct spu_reg128) },
{ "lslr", NULL, spufs_lslr_get, 19 },
{ "decr", NULL, spufs_decr_get, 19 },
{ "decr_status", NULL, spufs_decr_status_get, 19 },
{ "mem", __spufs_mem_read, NULL, LS_SIZE, },
{ "signal1", __spufs_signal1_read, NULL, sizeof(u32) },
{ "mem", spufs_mem_dump, NULL, LS_SIZE, },
{ "signal1", spufs_signal1_dump, NULL, sizeof(u32) },
{ "signal1_type", NULL, spufs_signal1_type_get, 19 },
{ "signal2", __spufs_signal2_read, NULL, sizeof(u32) },
{ "signal2", spufs_signal2_dump, NULL, sizeof(u32) },
{ "signal2_type", NULL, spufs_signal2_type_get, 19 },
{ "event_mask", NULL, spufs_event_mask_get, 19 },
{ "event_status", NULL, spufs_event_status_get, 19 },
{ "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) },
{ "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) },
{ "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)},
{ "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)},
{ "proxydma_info", __spufs_proxydma_info_read,
{ "mbox_info", spufs_mbox_info_dump, NULL, sizeof(u32) },
{ "ibox_info", spufs_ibox_info_dump, NULL, sizeof(u32) },
{ "wbox_info", spufs_wbox_info_dump, NULL, 4 * sizeof(u32)},
{ "dma_info", spufs_dma_info_dump, NULL, sizeof(struct spu_dma_info)},
{ "proxydma_info", spufs_proxydma_info_dump,
NULL, sizeof(struct spu_proxydma_info)},
{ "object-id", NULL, spufs_object_id_get, 19 },
{ "npc", NULL, spufs_npc_get, 19 },

View File

@ -337,8 +337,7 @@ void spufs_dma_callback(struct spu *spu, int type);
extern struct spu_coredump_calls spufs_coredump_calls;
struct spufs_coredump_reader {
char *name;
ssize_t (*read)(struct spu_context *ctx,
char __user *buffer, size_t size, loff_t *pos);
ssize_t (*dump)(struct spu_context *ctx, struct coredump_params *cprm);
u64 (*get)(struct spu_context *ctx);
size_t size;
};

View File

@ -440,3 +440,4 @@
435 common clone3 sys_clone3 sys_clone3
437 common openat2 sys_openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2 sys_faccessat2

View File

@ -440,3 +440,4 @@
# 435 reserved for clone3
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -483,3 +483,4 @@
# 435 reserved for clone3
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -442,3 +442,4 @@
435 i386 clone3 sys_clone3
437 i386 openat2 sys_openat2
438 i386 pidfd_getfd sys_pidfd_getfd
439 i386 faccessat2 sys_faccessat2

View File

@ -359,6 +359,7 @@
435 common clone3 sys_clone3
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2
#
# x32-specific system call numbers start at 512 to avoid cache impact

View File

@ -350,7 +350,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
unsafe_put_user(*(__u64 *)set, (__u64 *)&frame->uc.uc_sigmask, Efault);
user_access_end();
if (__copy_siginfo_to_user32(&frame->info, &ksig->info, false))
if (__copy_siginfo_to_user32(&frame->info, &ksig->info))
return -EFAULT;
/* Set up registers for signal handler */

View File

@ -214,7 +214,11 @@ static inline bool in_compat_syscall(void)
#endif
struct compat_siginfo;
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
const kernel_siginfo_t *from, bool x32_ABI);
#ifdef CONFIG_X86_X32_ABI
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
const kernel_siginfo_t *from);
#define copy_siginfo_to_user32 copy_siginfo_to_user32
#endif /* CONFIG_X86_X32_ABI */
#endif /* _ASM_X86_COMPAT_H */

View File

@ -37,6 +37,7 @@
#include <asm/vm86.h>
#ifdef CONFIG_X86_64
#include <linux/compat.h>
#include <asm/proto.h>
#include <asm/ia32_unistd.h>
#endif /* CONFIG_X86_64 */
@ -511,6 +512,31 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
}
#endif /* CONFIG_X86_32 */
#ifdef CONFIG_X86_X32_ABI
static int x32_copy_siginfo_to_user(struct compat_siginfo __user *to,
const struct kernel_siginfo *from)
{
struct compat_siginfo new;
copy_siginfo_to_external32(&new, from);
if (from->si_signo == SIGCHLD) {
new._sifields._sigchld_x32._utime = from->si_utime;
new._sifields._sigchld_x32._stime = from->si_stime;
}
if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
return -EFAULT;
return 0;
}
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
const struct kernel_siginfo *from)
{
if (in_x32_syscall())
return x32_copy_siginfo_to_user(to, from);
return __copy_siginfo_to_user32(to, from);
}
#endif /* CONFIG_X86_X32_ABI */
static int x32_setup_rt_frame(struct ksignal *ksig,
compat_sigset_t *set,
struct pt_regs *regs)
@ -543,7 +569,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig,
user_access_end();
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
if (__copy_siginfo_to_user32(&frame->info, &ksig->info, true))
if (x32_copy_siginfo_to_user(&frame->info, &ksig->info))
return -EFAULT;
}

View File

@ -408,3 +408,4 @@
435 common clone3 sys_clone3
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2

View File

@ -176,6 +176,7 @@ struct fsync_iocb {
struct file *file;
struct work_struct work;
bool datasync;
struct cred *creds;
};
struct poll_iocb {
@ -1589,8 +1590,11 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb,
static void aio_fsync_work(struct work_struct *work)
{
struct aio_kiocb *iocb = container_of(work, struct aio_kiocb, fsync.work);
const struct cred *old_cred = override_creds(iocb->fsync.creds);
iocb->ki_res.res = vfs_fsync(iocb->fsync.file, iocb->fsync.datasync);
revert_creds(old_cred);
put_cred(iocb->fsync.creds);
iocb_put(iocb);
}
@ -1604,6 +1608,10 @@ static int aio_fsync(struct fsync_iocb *req, const struct iocb *iocb,
if (unlikely(!req->file->f_op->fsync))
return -EINVAL;
req->creds = prepare_creds();
if (!req->creds)
return -ENOMEM;
req->datasync = datasync;
INIT_WORK(&req->work, aio_fsync_work);
schedule_work(&req->work);

View File

@ -1488,7 +1488,6 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) {
u32 __user *header = (u32 __user *) vma->vm_start;
u32 word;
mm_segment_t fs = get_fs();
/*
* Doing it this way gets the constant folded by GCC.
*/
@ -1501,14 +1500,8 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
magic.elfmag[EI_MAG1] = ELFMAG1;
magic.elfmag[EI_MAG2] = ELFMAG2;
magic.elfmag[EI_MAG3] = ELFMAG3;
/*
* Switch to the user "segment" for get_user(),
* then put back what elf_core_dump() had in place.
*/
set_fs(USER_DS);
if (unlikely(get_user(word, header)))
word = 0;
set_fs(fs);
if (word == magic.cmp)
return PAGE_SIZE;
}
@ -1689,10 +1682,7 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
const kernel_siginfo_t *siginfo)
{
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo);
set_fs(old_fs);
copy_siginfo_to_external(csigdata, siginfo);
fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata);
}
@ -2319,7 +2309,6 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
static int elf_core_dump(struct coredump_params *cprm)
{
int has_dumped = 0;
mm_segment_t fs;
int segs, i;
size_t vma_data_size = 0;
struct vm_area_struct *vma, *gate_vma;
@ -2368,13 +2357,10 @@ static int elf_core_dump(struct coredump_params *cprm)
* notes. This also sets up the file header.
*/
if (!fill_note_info(&elf, e_phnum, &info, cprm->siginfo, cprm->regs))
goto cleanup;
goto end_coredump;
has_dumped = 1;
fs = get_fs();
set_fs(KERNEL_DS);
offset += sizeof(elf); /* Elf header */
offset += segs * sizeof(struct elf_phdr); /* Program headers */
@ -2502,9 +2488,6 @@ static int elf_core_dump(struct coredump_params *cprm)
}
end_coredump:
set_fs(fs);
cleanup:
free_note_info(&info);
kfree(shdr4extnum);
kvfree(vma_filesz);

View File

@ -1549,7 +1549,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
{
#define NUM_NOTES 6
int has_dumped = 0;
mm_segment_t fs;
int segs;
int i;
struct vm_area_struct *vma;
@ -1589,31 +1588,31 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
/* alloc memory for large data structures: too large to be on stack */
elf = kmalloc(sizeof(*elf), GFP_KERNEL);
if (!elf)
goto cleanup;
goto end_coredump;
prstatus = kzalloc(sizeof(*prstatus), GFP_KERNEL);
if (!prstatus)
goto cleanup;
goto end_coredump;
psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
if (!psinfo)
goto cleanup;
goto end_coredump;
notes = kmalloc_array(NUM_NOTES, sizeof(struct memelfnote),
GFP_KERNEL);
if (!notes)
goto cleanup;
goto end_coredump;
fpu = kmalloc(sizeof(*fpu), GFP_KERNEL);
if (!fpu)
goto cleanup;
goto end_coredump;
#ifdef ELF_CORE_COPY_XFPREGS
xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL);
if (!xfpu)
goto cleanup;
goto end_coredump;
#endif
for (ct = current->mm->core_state->dumper.next;
ct; ct = ct->next) {
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
goto cleanup;
goto end_coredump;
tmp->thread = ct->task;
list_add(&tmp->list, &thread_list);
@ -1678,9 +1677,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
"LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu);
#endif
fs = get_fs();
set_fs(KERNEL_DS);
offset += sizeof(*elf); /* Elf header */
offset += segs * sizeof(struct elf_phdr); /* Program headers */
@ -1788,9 +1784,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
}
end_coredump:
set_fs(fs);
cleanup:
while (!list_empty(&thread_list)) {
struct list_head *tmp = thread_list.next;
list_del(tmp);

View File

@ -483,6 +483,9 @@ int cdev_add(struct cdev *p, dev_t dev, unsigned count)
p->dev = dev;
p->count = count;
if (WARN_ON(dev == WHITEOUT_DEV))
return -EBUSY;
error = kobj_map(cdev_map, dev, count, NULL,
exact_match, exact_lock, p);
if (error)

View File

@ -43,7 +43,7 @@
*/
#define user_long_t compat_long_t
#define user_siginfo_t compat_siginfo_t
#define copy_siginfo_to_user copy_siginfo_to_user32
#define copy_siginfo_to_external copy_siginfo_to_external32
/*
* The machine-dependent core note format types are defined in elfcore-compat.h,

View File

@ -42,7 +42,6 @@ static const struct constant_table common_set_sb_flag[] = {
{ "dirsync", SB_DIRSYNC },
{ "lazytime", SB_LAZYTIME },
{ "mand", SB_MANDLOCK },
{ "posixacl", SB_POSIXACL },
{ "ro", SB_RDONLY },
{ "sync", SB_SYNCHRONOUS },
{ },
@ -53,44 +52,15 @@ static const struct constant_table common_clear_sb_flag[] = {
{ "nolazytime", SB_LAZYTIME },
{ "nomand", SB_MANDLOCK },
{ "rw", SB_RDONLY },
{ "silent", SB_SILENT },
{ },
};
static const char *const forbidden_sb_flag[] = {
"bind",
"dev",
"exec",
"move",
"noatime",
"nodev",
"nodiratime",
"noexec",
"norelatime",
"nostrictatime",
"nosuid",
"private",
"rec",
"relatime",
"remount",
"shared",
"slave",
"strictatime",
"suid",
"unbindable",
};
/*
* Check for a common mount option that manipulates s_flags.
*/
static int vfs_parse_sb_flag(struct fs_context *fc, const char *key)
{
unsigned int token;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(forbidden_sb_flag); i++)
if (strcmp(key, forbidden_sb_flag[i]) == 0)
return -EINVAL;
token = lookup_constant(common_set_sb_flag, key, 0);
if (token) {

View File

@ -126,7 +126,6 @@ extern struct open_how build_open_how(int flags, umode_t mode);
extern int build_open_flags(const struct open_how *how, struct open_flags *op);
long do_sys_ftruncate(unsigned int fd, loff_t length, int small);
long do_faccessat(int dfd, const char __user *filename, int mode);
int do_fchmodat(int dfd, const char __user *filename, umode_t mode);
int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
int flag);

View File

@ -9,7 +9,13 @@ struct mnt_namespace {
atomic_t count;
struct ns_common ns;
struct mount * root;
/*
* Traversal and modification of .list is protected by either
* - taking namespace_sem for write, OR
* - taking namespace_sem for read AND taking .ns_lock.
*/
struct list_head list;
spinlock_t ns_lock;
struct user_namespace *user_ns;
struct ucounts *ucounts;
u64 seq; /* Sequence number to prevent loops */
@ -133,9 +139,7 @@ struct proc_mounts {
struct mnt_namespace *ns;
struct path root;
int (*show)(struct seq_file *, struct vfsmount *);
void *cached_mount;
u64 cached_event;
loff_t cached_index;
struct mount cursor;
};
extern const struct seq_operations mounts_op;
@ -153,3 +157,5 @@ static inline bool is_anon_ns(struct mnt_namespace *ns)
{
return ns->seq == 0;
}
extern void mnt_cursor_del(struct mnt_namespace *ns, struct mount *cursor);

View File

@ -3589,12 +3589,14 @@ EXPORT_SYMBOL(user_path_create);
int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV;
int error = may_create(dir, dentry);
if (error)
return error;
if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
if ((S_ISCHR(mode) || S_ISBLK(mode)) && !is_whiteout &&
!capable(CAP_MKNOD))
return -EPERM;
if (!dir->i_op->mknod)
@ -4429,9 +4431,6 @@ static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
(flags & RENAME_EXCHANGE))
return -EINVAL;
if ((flags & RENAME_WHITEOUT) && !capable(CAP_MKNOD))
return -EPERM;
if (flags & RENAME_EXCHANGE)
target_flags = 0;
@ -4567,20 +4566,6 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna
return do_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
}
int vfs_whiteout(struct inode *dir, struct dentry *dentry)
{
int error = may_create(dir, dentry);
if (error)
return error;
if (!dir->i_op->mknod)
return -EPERM;
return dir->i_op->mknod(dir, dentry,
S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV);
}
EXPORT_SYMBOL(vfs_whiteout);
int readlink_copy(char __user *buffer, int buflen, const char *link)
{
int len = PTR_ERR(link);

View File

@ -650,6 +650,21 @@ struct vfsmount *lookup_mnt(const struct path *path)
return m;
}
static inline void lock_ns_list(struct mnt_namespace *ns)
{
spin_lock(&ns->ns_lock);
}
static inline void unlock_ns_list(struct mnt_namespace *ns)
{
spin_unlock(&ns->ns_lock);
}
static inline bool mnt_is_cursor(struct mount *mnt)
{
return mnt->mnt.mnt_flags & MNT_CURSOR;
}
/*
* __is_local_mountpoint - Test to see if dentry is a mountpoint in the
* current mount namespace.
@ -675,11 +690,15 @@ bool __is_local_mountpoint(struct dentry *dentry)
goto out;
down_read(&namespace_sem);
lock_ns_list(ns);
list_for_each_entry(mnt, &ns->list, mnt_list) {
if (mnt_is_cursor(mnt))
continue;
is_covered = (mnt->mnt_mountpoint == dentry);
if (is_covered)
break;
}
unlock_ns_list(ns);
up_read(&namespace_sem);
out:
return is_covered;
@ -1267,46 +1286,71 @@ struct vfsmount *mnt_clone_internal(const struct path *path)
}
#ifdef CONFIG_PROC_FS
static struct mount *mnt_list_next(struct mnt_namespace *ns,
struct list_head *p)
{
struct mount *mnt, *ret = NULL;
lock_ns_list(ns);
list_for_each_continue(p, &ns->list) {
mnt = list_entry(p, typeof(*mnt), mnt_list);
if (!mnt_is_cursor(mnt)) {
ret = mnt;
break;
}
}
unlock_ns_list(ns);
return ret;
}
/* iterator; we want it to have access to namespace_sem, thus here... */
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct proc_mounts *p = m->private;
struct list_head *prev;
down_read(&namespace_sem);
if (p->cached_event == p->ns->event) {
void *v = p->cached_mount;
if (*pos == p->cached_index)
return v;
if (*pos == p->cached_index + 1) {
v = seq_list_next(v, &p->ns->list, &p->cached_index);
return p->cached_mount = v;
}
if (!*pos) {
prev = &p->ns->list;
} else {
prev = &p->cursor.mnt_list;
/* Read after we'd reached the end? */
if (list_empty(prev))
return NULL;
}
p->cached_event = p->ns->event;
p->cached_mount = seq_list_start(&p->ns->list, *pos);
p->cached_index = *pos;
return p->cached_mount;
return mnt_list_next(p->ns, prev);
}
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
struct proc_mounts *p = m->private;
struct mount *mnt = v;
p->cached_mount = seq_list_next(v, &p->ns->list, pos);
p->cached_index = *pos;
return p->cached_mount;
++*pos;
return mnt_list_next(p->ns, &mnt->mnt_list);
}
static void m_stop(struct seq_file *m, void *v)
{
struct proc_mounts *p = m->private;
struct mount *mnt = v;
lock_ns_list(p->ns);
if (mnt)
list_move_tail(&p->cursor.mnt_list, &mnt->mnt_list);
else
list_del_init(&p->cursor.mnt_list);
unlock_ns_list(p->ns);
up_read(&namespace_sem);
}
static int m_show(struct seq_file *m, void *v)
{
struct proc_mounts *p = m->private;
struct mount *r = list_entry(v, struct mount, mnt_list);
struct mount *r = v;
return p->show(m, &r->mnt);
}
@ -1316,6 +1360,15 @@ const struct seq_operations mounts_op = {
.stop = m_stop,
.show = m_show,
};
void mnt_cursor_del(struct mnt_namespace *ns, struct mount *cursor)
{
down_read(&namespace_sem);
lock_ns_list(ns);
list_del(&cursor->mnt_list);
unlock_ns_list(ns);
up_read(&namespace_sem);
}
#endif /* CONFIG_PROC_FS */
/**
@ -3232,6 +3285,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, bool a
atomic_set(&new_ns->count, 1);
INIT_LIST_HEAD(&new_ns->list);
init_waitqueue_head(&new_ns->poll);
spin_lock_init(&new_ns->ns_lock);
new_ns->user_ns = get_user_ns(user_ns);
new_ns->ucounts = ucounts;
return new_ns;
@ -3872,10 +3926,14 @@ static bool mnt_already_visible(struct mnt_namespace *ns,
bool visible = false;
down_read(&namespace_sem);
lock_ns_list(ns);
list_for_each_entry(mnt, &ns->list, mnt_list) {
struct mount *child;
int mnt_flags;
if (mnt_is_cursor(mnt))
continue;
if (mnt->mnt.mnt_sb->s_type != sb->s_type)
continue;
@ -3923,6 +3981,7 @@ static bool mnt_already_visible(struct mnt_namespace *ns,
next: ;
}
found:
unlock_ns_list(ns);
up_read(&namespace_sem);
return visible;
}

View File

@ -345,21 +345,14 @@ SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
* We do this by temporarily clearing all FS-related capabilities and
* switching the fsuid/fsgid around to the real ones.
*/
long do_faccessat(int dfd, const char __user *filename, int mode)
static const struct cred *access_override_creds(void)
{
const struct cred *old_cred;
struct cred *override_cred;
struct path path;
struct inode *inode;
int res;
unsigned int lookup_flags = LOOKUP_FOLLOW;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
override_cred = prepare_creds();
if (!override_cred)
return -ENOMEM;
return NULL;
override_cred->fsuid = override_cred->uid;
override_cred->fsgid = override_cred->gid;
@ -394,6 +387,38 @@ long do_faccessat(int dfd, const char __user *filename, int mode)
override_cred->non_rcu = 1;
old_cred = override_creds(override_cred);
/* override_cred() gets its own ref */
put_cred(override_cred);
return old_cred;
}
long do_faccessat(int dfd, const char __user *filename, int mode, int flags)
{
struct path path;
struct inode *inode;
int res;
unsigned int lookup_flags = LOOKUP_FOLLOW;
const struct cred *old_cred = NULL;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
if (flags & ~(AT_EACCESS | AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
return -EINVAL;
if (flags & AT_SYMLINK_NOFOLLOW)
lookup_flags &= ~LOOKUP_FOLLOW;
if (flags & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
if (!(flags & AT_EACCESS)) {
old_cred = access_override_creds();
if (!old_cred)
return -ENOMEM;
}
retry:
res = user_path_at(dfd, filename, lookup_flags, &path);
if (res)
@ -435,19 +460,26 @@ long do_faccessat(int dfd, const char __user *filename, int mode)
goto retry;
}
out:
revert_creds(old_cred);
put_cred(override_cred);
if (old_cred)
revert_creds(old_cred);
return res;
}
SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
{
return do_faccessat(dfd, filename, mode);
return do_faccessat(dfd, filename, mode, 0);
}
SYSCALL_DEFINE4(faccessat2, int, dfd, const char __user *, filename, int, mode,
int, flags)
{
return do_faccessat(dfd, filename, mode, flags);
}
SYSCALL_DEFINE2(access, const char __user *, filename, int, mode)
{
return do_faccessat(AT_FDCWD, filename, mode);
return do_faccessat(AT_FDCWD, filename, mode, 0);
}
int ksys_chdir(const char __user *filename)

View File

@ -283,7 +283,8 @@ static int mounts_open_common(struct inode *inode, struct file *file,
p->ns = ns;
p->root = root;
p->show = show;
p->cached_event = ~0ULL;
INIT_LIST_HEAD(&p->cursor.mnt_list);
p->cursor.mnt.mnt_flags = MNT_CURSOR;
return 0;
@ -300,6 +301,7 @@ static int mounts_release(struct inode *inode, struct file *file)
struct seq_file *m = file->private_data;
struct proc_mounts *p = m->private;
path_put(&p->root);
mnt_cursor_del(p->ns, &p->cursor);
put_mnt_ns(p->ns);
return seq_release_private(inode, file);
}

View File

@ -22,6 +22,7 @@
#include <asm/unistd.h>
#include "internal.h"
#include "mount.h"
/**
* generic_fillattr - Fill in the basic attributes from the inode struct
@ -70,11 +71,11 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
memset(stat, 0, sizeof(*stat));
stat->result_mask |= STATX_BASIC_STATS;
request_mask &= STATX_ALL;
query_flags &= KSTAT_QUERY_FLAGS;
/* allow the fs to override these if it really wants to */
if (IS_NOATIME(inode))
/* SB_NOATIME means filesystem supplies dummy atime value */
if (inode->i_sb->s_flags & SB_NOATIME)
stat->result_mask &= ~STATX_ATIME;
if (IS_AUTOMOUNT(inode))
stat->attributes |= STATX_ATTR_AUTOMOUNT;
@ -199,6 +200,11 @@ int vfs_statx(int dfd, const char __user *filename, int flags,
goto out;
error = vfs_getattr(&path, stat, request_mask, flags);
stat->mnt_id = real_mount(path.mnt)->mnt_id;
stat->result_mask |= STATX_MNT_ID;
if (path.mnt->mnt_root == path.dentry)
stat->attributes |= STATX_ATTR_MOUNT_ROOT;
stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT;
path_put(&path);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
@ -563,6 +569,7 @@ cp_statx(const struct kstat *stat, struct statx __user *buffer)
tmp.stx_rdev_minor = MINOR(stat->rdev);
tmp.stx_dev_major = MAJOR(stat->dev);
tmp.stx_dev_minor = MINOR(stat->dev);
tmp.stx_mnt_id = stat->mnt_id;
return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}

View File

@ -95,13 +95,13 @@ long do_utimes(int dfd, const char __user *filename, struct timespec64 *times,
goto out;
}
if (flags & ~AT_SYMLINK_NOFOLLOW)
if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
goto out;
if (filename == NULL && dfd != AT_FDCWD) {
struct fd f;
if (flags & AT_SYMLINK_NOFOLLOW)
if (flags)
goto out;
f = fdget(dfd);
@ -117,6 +117,8 @@ long do_utimes(int dfd, const char __user *filename, struct timespec64 *times,
if (!(flags & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
if (flags & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
retry:
error = user_path_at(dfd, filename, lookup_flags, &path);
if (error)

View File

@ -402,8 +402,15 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size);
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
unsigned long bitmap_size);
int copy_siginfo_from_user32(kernel_siginfo_t *to, const struct compat_siginfo __user *from);
int copy_siginfo_to_user32(struct compat_siginfo __user *to, const kernel_siginfo_t *from);
void copy_siginfo_to_external32(struct compat_siginfo *to,
const struct kernel_siginfo *from);
int copy_siginfo_from_user32(kernel_siginfo_t *to,
const struct compat_siginfo __user *from);
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
const kernel_siginfo_t *from);
#ifndef copy_siginfo_to_user32
#define copy_siginfo_to_user32 __copy_siginfo_to_user32
#endif
int get_compat_sigevent(struct sigevent *event,
const struct compat_sigevent __user *u_event);

View File

@ -44,6 +44,9 @@ static inline int devcgroup_inode_mknod(int mode, dev_t dev)
if (!S_ISBLK(mode) && !S_ISCHR(mode))
return 0;
if (S_ISCHR(mode) && dev == WHITEOUT_DEV)
return 0;
if (S_ISBLK(mode))
type = DEVCG_DEV_BLOCK;
else

View File

@ -1731,7 +1731,11 @@ extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct ino
extern int vfs_rmdir(struct inode *, struct dentry *);
extern int vfs_unlink(struct inode *, struct dentry *, struct inode **);
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
extern int vfs_whiteout(struct inode *, struct dentry *);
static inline int vfs_whiteout(struct inode *dir, struct dentry *dentry)
{
return vfs_mknod(dir, dentry, S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV);
}
extern struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode,
int open_flag);

View File

@ -50,7 +50,8 @@ struct fs_context;
#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME )
#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED | \
MNT_CURSOR)
#define MNT_INTERNAL 0x4000
@ -64,6 +65,7 @@ struct fs_context;
#define MNT_SYNC_UMOUNT 0x2000000
#define MNT_MARKED 0x4000000
#define MNT_UMOUNT 0x8000000
#define MNT_CURSOR 0x10000000
struct vfsmount {
struct dentry *mnt_root; /* root of the mounted tree */

View File

@ -24,6 +24,14 @@ static inline void clear_siginfo(kernel_siginfo_t *info)
#define SI_EXPANSION_SIZE (sizeof(struct siginfo) - sizeof(struct kernel_siginfo))
static inline void copy_siginfo_to_external(siginfo_t *to,
const kernel_siginfo_t *from)
{
memcpy(to, from, sizeof(*from));
memset(((char *)to) + sizeof(struct kernel_siginfo), 0,
SI_EXPANSION_SIZE);
}
int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from);
int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from);

View File

@ -47,6 +47,7 @@ struct kstat {
struct timespec64 ctime;
struct timespec64 btime; /* File creation time */
u64 blocks;
u64 mnt_id;
};
#endif

View File

@ -428,6 +428,8 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length);
#endif
asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode);
asmlinkage long sys_faccessat2(int dfd, const char __user *filename, int mode,
int flags);
asmlinkage long sys_chdir(const char __user *filename);
asmlinkage long sys_fchdir(unsigned int fd);
asmlinkage long sys_chroot(const char __user *filename);
@ -1333,11 +1335,11 @@ static inline int ksys_chmod(const char __user *filename, umode_t mode)
return do_fchmodat(AT_FDCWD, filename, mode);
}
extern long do_faccessat(int dfd, const char __user *filename, int mode);
long do_faccessat(int dfd, const char __user *filename, int mode, int flags);
static inline long ksys_access(const char __user *filename, int mode)
{
return do_faccessat(AT_FDCWD, filename, mode);
return do_faccessat(AT_FDCWD, filename, mode, 0);
}
extern int do_fchownat(int dfd, const char __user *filename, uid_t user,

View File

@ -855,9 +855,11 @@ __SYSCALL(__NR_clone3, sys_clone3)
__SYSCALL(__NR_openat2, sys_openat2)
#define __NR_pidfd_getfd 438
__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
#define __NR_faccessat2 439
__SYSCALL(__NR_faccessat2, sys_faccessat2)
#undef __NR_syscalls
#define __NR_syscalls 439
#define __NR_syscalls 440
/*
* 32 bit systems traditionally used different

View File

@ -84,10 +84,20 @@
#define DN_ATTRIB 0x00000020 /* File changed attibutes */
#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
/*
* The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is
* meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
* unlinkat. The two functions do completely different things and therefore,
* the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to
* faccessat would be undefined behavior and thus treating it equivalent to
* AT_EACCESS is valid undefined behavior.
*/
#define AT_FDCWD -100 /* Special value used to indicate
openat should use the current
working directory. */
#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
#define AT_EACCESS 0x200 /* Test access permitted for
effective IDs, not real IDs. */
#define AT_REMOVEDIR 0x200 /* Remove directory instead of
unlinking file. */
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */

View File

@ -123,7 +123,10 @@ struct statx {
__u32 stx_dev_major; /* ID of device containing file [uncond] */
__u32 stx_dev_minor;
/* 0x90 */
__u64 __spare2[14]; /* Spare space for future expansion */
__u64 stx_mnt_id;
__u64 __spare2;
/* 0xa0 */
__u64 __spare3[12]; /* Spare space for future expansion */
/* 0x100 */
};
@ -148,9 +151,19 @@ struct statx {
#define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */
#define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */
#define STATX_BTIME 0x00000800U /* Want/got stx_btime */
#define STATX_ALL 0x00000fffU /* All currently supported flags */
#define STATX_MNT_ID 0x00001000U /* Got stx_mnt_id */
#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */
#ifndef __KERNEL__
/*
* This is deprecated, and shall remain the same value in the future. To avoid
* confusion please use the equivalent (STATX_BASIC_STATS | STATX_BTIME)
* instead.
*/
#define STATX_ALL 0x00000fffU
#endif
/*
* Attributes to be found in stx_attributes and masked in stx_attributes_mask.
*
@ -168,6 +181,7 @@ struct statx {
#define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */
#define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */
#define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */
#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */
#define STATX_ATTR_VERITY 0x00100000 /* [I] Verity protected file */

View File

@ -3235,94 +3235,94 @@ int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)
}
#ifdef CONFIG_COMPAT
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
const struct kernel_siginfo *from)
#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION)
/**
* copy_siginfo_to_external32 - copy a kernel siginfo into a compat user siginfo
* @to: compat siginfo destination
* @from: kernel siginfo source
*
* Note: This function does not work properly for the SIGCHLD on x32, but
* fortunately it doesn't have to. The only valid callers for this function are
* copy_siginfo_to_user32, which is overriden for x32 and the coredump code.
* The latter does not care because SIGCHLD will never cause a coredump.
*/
void copy_siginfo_to_external32(struct compat_siginfo *to,
const struct kernel_siginfo *from)
{
return __copy_siginfo_to_user32(to, from, in_x32_syscall());
}
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
const struct kernel_siginfo *from, bool x32_ABI)
#endif
{
struct compat_siginfo new;
memset(&new, 0, sizeof(new));
memset(to, 0, sizeof(*to));
new.si_signo = from->si_signo;
new.si_errno = from->si_errno;
new.si_code = from->si_code;
to->si_signo = from->si_signo;
to->si_errno = from->si_errno;
to->si_code = from->si_code;
switch(siginfo_layout(from->si_signo, from->si_code)) {
case SIL_KILL:
new.si_pid = from->si_pid;
new.si_uid = from->si_uid;
to->si_pid = from->si_pid;
to->si_uid = from->si_uid;
break;
case SIL_TIMER:
new.si_tid = from->si_tid;
new.si_overrun = from->si_overrun;
new.si_int = from->si_int;
to->si_tid = from->si_tid;
to->si_overrun = from->si_overrun;
to->si_int = from->si_int;
break;
case SIL_POLL:
new.si_band = from->si_band;
new.si_fd = from->si_fd;
to->si_band = from->si_band;
to->si_fd = from->si_fd;
break;
case SIL_FAULT:
new.si_addr = ptr_to_compat(from->si_addr);
to->si_addr = ptr_to_compat(from->si_addr);
#ifdef __ARCH_SI_TRAPNO
new.si_trapno = from->si_trapno;
to->si_trapno = from->si_trapno;
#endif
break;
case SIL_FAULT_MCEERR:
new.si_addr = ptr_to_compat(from->si_addr);
to->si_addr = ptr_to_compat(from->si_addr);
#ifdef __ARCH_SI_TRAPNO
new.si_trapno = from->si_trapno;
to->si_trapno = from->si_trapno;
#endif
new.si_addr_lsb = from->si_addr_lsb;
to->si_addr_lsb = from->si_addr_lsb;
break;
case SIL_FAULT_BNDERR:
new.si_addr = ptr_to_compat(from->si_addr);
to->si_addr = ptr_to_compat(from->si_addr);
#ifdef __ARCH_SI_TRAPNO
new.si_trapno = from->si_trapno;
to->si_trapno = from->si_trapno;
#endif
new.si_lower = ptr_to_compat(from->si_lower);
new.si_upper = ptr_to_compat(from->si_upper);
to->si_lower = ptr_to_compat(from->si_lower);
to->si_upper = ptr_to_compat(from->si_upper);
break;
case SIL_FAULT_PKUERR:
new.si_addr = ptr_to_compat(from->si_addr);
to->si_addr = ptr_to_compat(from->si_addr);
#ifdef __ARCH_SI_TRAPNO
new.si_trapno = from->si_trapno;
to->si_trapno = from->si_trapno;
#endif
new.si_pkey = from->si_pkey;
to->si_pkey = from->si_pkey;
break;
case SIL_CHLD:
new.si_pid = from->si_pid;
new.si_uid = from->si_uid;
new.si_status = from->si_status;
#ifdef CONFIG_X86_X32_ABI
if (x32_ABI) {
new._sifields._sigchld_x32._utime = from->si_utime;
new._sifields._sigchld_x32._stime = from->si_stime;
} else
#endif
{
new.si_utime = from->si_utime;
new.si_stime = from->si_stime;
}
to->si_pid = from->si_pid;
to->si_uid = from->si_uid;
to->si_status = from->si_status;
to->si_utime = from->si_utime;
to->si_stime = from->si_stime;
break;
case SIL_RT:
new.si_pid = from->si_pid;
new.si_uid = from->si_uid;
new.si_int = from->si_int;
to->si_pid = from->si_pid;
to->si_uid = from->si_uid;
to->si_int = from->si_int;
break;
case SIL_SYS:
new.si_call_addr = ptr_to_compat(from->si_call_addr);
new.si_syscall = from->si_syscall;
new.si_arch = from->si_arch;
to->si_call_addr = ptr_to_compat(from->si_call_addr);
to->si_syscall = from->si_syscall;
to->si_arch = from->si_arch;
break;
}
}
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
const struct kernel_siginfo *from)
{
struct compat_siginfo new;
copy_siginfo_to_external32(&new, from);
if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
return -EFAULT;
return 0;
}

View File

@ -216,7 +216,7 @@ int main(int argc, char **argv)
struct statx stx;
int ret, raw = 0, atflag = AT_SYMLINK_NOFOLLOW;
unsigned int mask = STATX_ALL;
unsigned int mask = STATX_BASIC_STATS | STATX_BTIME;
for (argv++; *argv; argv++) {
if (strcmp(*argv, "-F") == 0) {

View File

@ -148,9 +148,18 @@ struct statx {
#define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */
#define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */
#define STATX_BTIME 0x00000800U /* Want/got stx_btime */
#define STATX_ALL 0x00000fffU /* All currently supported flags */
#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */
#ifndef __KERNEL__
/*
* This is deprecated, and shall remain the same value in the future. To avoid
* confusion please use the equivalent (STATX_BASIC_STATS | STATX_BTIME)
* instead.
*/
#define STATX_ALL 0x00000fffU
#endif
/*
* Attributes to be found in stx_attributes and masked in stx_attributes_mask.
*