diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index 55f350a0c589..d0340713c0d3 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include @@ -119,6 +120,7 @@ static fo_stat_t shm_stat; static fo_close_t shm_close; static fo_chmod_t shm_chmod; static fo_chown_t shm_chown; +static fo_seek_t shm_seek; /* File descriptor operations. */ static struct fileops shm_ops = { @@ -133,7 +135,8 @@ static struct fileops shm_ops = { .fo_chmod = shm_chmod, .fo_chown = shm_chown, .fo_sendfile = invfo_sendfile, - .fo_flags = DFLAG_PASSABLE + .fo_seek = shm_seek, + .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE }; FEATURE(posix_shm, "POSIX shared memory"); @@ -232,20 +235,97 @@ uiomove_object(vm_object_t obj, off_t obj_size, struct uio *uio) return (error); } +static int +shm_seek(struct file *fp, off_t offset, int whence, struct thread *td) +{ + struct shmfd *shmfd; + off_t foffset; + int error; + + shmfd = fp->f_data; + foffset = foffset_lock(fp, 0); + error = 0; + switch (whence) { + case L_INCR: + if (foffset < 0 || + (offset > 0 && foffset > OFF_MAX - offset)) { + error = EOVERFLOW; + break; + } + offset += foffset; + break; + case L_XTND: + if (offset > 0 && shmfd->shm_size > OFF_MAX - offset) { + error = EOVERFLOW; + break; + } + offset += shmfd->shm_size; + break; + case L_SET: + break; + default: + error = EINVAL; + } + if (error == 0) { + if (offset < 0 || offset > shmfd->shm_size) + error = EINVAL; + else + *(off_t *)(td->td_retval) = offset; + } + foffset_unlock(fp, offset, error != 0 ? FOF_NOUPDATE : 0); + return (error); +} + static int shm_read(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags, struct thread *td) { + struct shmfd *shmfd; + void *rl_cookie; + int error; - return (EOPNOTSUPP); + shmfd = fp->f_data; + foffset_lock_uio(fp, uio, flags); + rl_cookie = rangelock_rlock(&shmfd->shm_rl, uio->uio_offset, + uio->uio_offset + uio->uio_resid, &shmfd->shm_mtx); +#ifdef MAC + error = mac_posixshm_check_read(active_cred, fp->f_cred, shmfd); + if (error) + return (error); +#endif + error = uiomove_object(shmfd->shm_object, shmfd->shm_size, uio); + rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx); + foffset_unlock_uio(fp, uio, flags); + return (error); } static int shm_write(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags, struct thread *td) { + struct shmfd *shmfd; + void *rl_cookie; + int error; - return (EOPNOTSUPP); + shmfd = fp->f_data; +#ifdef MAC + error = mac_posixshm_check_write(active_cred, fp->f_cred, shmfd); + if (error) + return (error); +#endif + foffset_lock_uio(fp, uio, flags); + if ((flags & FOF_OFFSET) == 0) { + rl_cookie = rangelock_wlock(&shmfd->shm_rl, 0, OFF_MAX, + &shmfd->shm_mtx); + } else { + rl_cookie = rangelock_wlock(&shmfd->shm_rl, uio->uio_offset, + uio->uio_offset + uio->uio_resid, &shmfd->shm_mtx); + } + + error = uiomove_object(shmfd->shm_object, shmfd->shm_size, uio); + rangelock_unlock(&shmfd->shm_rl, rl_cookie, &shmfd->shm_mtx); + foffset_unlock_uio(fp, uio, flags); + return (error); } static int @@ -471,6 +551,8 @@ shm_alloc(struct ucred *ucred, mode_t mode) shmfd->shm_atime = shmfd->shm_mtime = shmfd->shm_ctime = shmfd->shm_birthtime; refcount_init(&shmfd->shm_refs, 1); + mtx_init(&shmfd->shm_mtx, "shmrl", NULL, MTX_DEF); + rangelock_init(&shmfd->shm_rl); #ifdef MAC mac_posixshm_init(shmfd); mac_posixshm_create(ucred, shmfd); @@ -495,6 +577,8 @@ shm_drop(struct shmfd *shmfd) #ifdef MAC mac_posixshm_destroy(shmfd); #endif + rangelock_destroy(&shmfd->shm_rl); + mtx_destroy(&shmfd->shm_mtx); vm_object_deallocate(shmfd->shm_object); free(shmfd, M_SHMFD); } diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h index 92aedea4ef75..77cb8bcb60c4 100644 --- a/sys/security/mac/mac_framework.h +++ b/sys/security/mac/mac_framework.h @@ -243,6 +243,8 @@ int mac_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, int prot, int flags); int mac_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, accmode_t accmode); +int mac_posixshm_check_read(struct ucred *active_cred, + struct ucred *file_cred, struct shmfd *shmfd); int mac_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, mode_t mode); int mac_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd, @@ -252,6 +254,8 @@ int mac_posixshm_check_stat(struct ucred *active_cred, int mac_posixshm_check_truncate(struct ucred *active_cred, struct ucred *file_cred, struct shmfd *shmfd); int mac_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd); +int mac_posixshm_check_write(struct ucred *active_cred, + struct ucred *file_cred, struct shmfd *shmfd); void mac_posixshm_create(struct ucred *cred, struct shmfd *shmfd); void mac_posixshm_destroy(struct shmfd *); void mac_posixshm_init(struct shmfd *); diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h index 090dc4058104..dadadb5828b3 100644 --- a/sys/security/mac/mac_policy.h +++ b/sys/security/mac/mac_policy.h @@ -363,6 +363,9 @@ typedef int (*mpo_posixshm_check_mmap_t)(struct ucred *cred, typedef int (*mpo_posixshm_check_open_t)(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel, accmode_t accmode); +typedef int (*mpo_posixshm_check_read_t)(struct ucred *active_cred, + struct ucred *file_cred, struct shmfd *shmfd, + struct label *shmlabel); typedef int (*mpo_posixshm_check_setmode_t)(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel, mode_t mode); @@ -377,6 +380,9 @@ typedef int (*mpo_posixshm_check_truncate_t)(struct ucred *active_cred, struct label *shmlabel); typedef int (*mpo_posixshm_check_unlink_t)(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel); +typedef int (*mpo_posixshm_check_write_t)(struct ucred *active_cred, + struct ucred *file_cred, struct shmfd *shmfd, + struct label *shmlabel); typedef void (*mpo_posixshm_create_t)(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel); typedef void (*mpo_posixshm_destroy_label_t)(struct label *label); @@ -818,11 +824,13 @@ struct mac_policy_ops { mpo_posixshm_check_create_t mpo_posixshm_check_create; mpo_posixshm_check_mmap_t mpo_posixshm_check_mmap; mpo_posixshm_check_open_t mpo_posixshm_check_open; + mpo_posixshm_check_read_t mpo_posixshm_check_read; mpo_posixshm_check_setmode_t mpo_posixshm_check_setmode; mpo_posixshm_check_setowner_t mpo_posixshm_check_setowner; mpo_posixshm_check_stat_t mpo_posixshm_check_stat; mpo_posixshm_check_truncate_t mpo_posixshm_check_truncate; mpo_posixshm_check_unlink_t mpo_posixshm_check_unlink; + mpo_posixshm_check_write_t mpo_posixshm_check_write; mpo_posixshm_create_t mpo_posixshm_create; mpo_posixshm_destroy_label_t mpo_posixshm_destroy_label; mpo_posixshm_init_label_t mpo_posixshm_init_label; diff --git a/sys/security/mac/mac_posix_shm.c b/sys/security/mac/mac_posix_shm.c index d5d15fc4248c..1202d46303a3 100644 --- a/sys/security/mac/mac_posix_shm.c +++ b/sys/security/mac/mac_posix_shm.c @@ -228,3 +228,37 @@ mac_posixshm_check_setowner(struct ucred *cred, struct shmfd *shmfd, uid_t uid, return (error); } + +MAC_CHECK_PROBE_DEFINE3(posixshm_check_read, "struct ucred *", + "struct ucred *", "struct shmfd *"); + +int +mac_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *shmfd) +{ + int error; + + MAC_POLICY_CHECK_NOSLEEP(posixshm_check_read, active_cred, + file_cred, shmfd, shmfd->shm_label); + MAC_CHECK_PROBE3(posixshm_check_read, error, active_cred, + file_cred, shmfd); + + return (error); +} + +MAC_CHECK_PROBE_DEFINE3(posixshm_check_write, "struct ucred *", + "struct ucred *", "struct shmfd *"); + +int +mac_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *shmfd) +{ + int error; + + MAC_POLICY_CHECK_NOSLEEP(posixshm_check_write, active_cred, + file_cred, shmfd, shmfd->shm_label); + MAC_CHECK_PROBE3(posixshm_check_write, error, active_cred, + file_cred, shmfd); + + return (error); +} diff --git a/sys/security/mac_biba/mac_biba.c b/sys/security/mac_biba/mac_biba.c index aa37fc79fa37..4216fea41476 100644 --- a/sys/security/mac_biba/mac_biba.c +++ b/sys/security/mac_biba/mac_biba.c @@ -1758,6 +1758,24 @@ biba_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, return (0); } +static int +biba_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *vp, struct label *shmlabel) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled || !revocation_enabled) + return (0); + + subj = SLOT(active_cred->cr_label); + obj = SLOT(shmlabel); + + if (!biba_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + static int biba_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel, mode_t mode) @@ -1848,6 +1866,24 @@ biba_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd, return (0); } +static int +biba_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *vp, struct label *shmlabel) +{ + struct mac_biba *subj, *obj; + + if (!biba_enabled || !revocation_enabled) + return (0); + + subj = SLOT(active_cred->cr_label); + obj = SLOT(shmlabel); + + if (!biba_dominate_effective(obj, subj)) + return (EACCES); + + return (0); +} + static void biba_posixshm_create(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel) @@ -3657,11 +3693,13 @@ static struct mac_policy_ops mac_biba_ops = .mpo_posixshm_check_mmap = biba_posixshm_check_mmap, .mpo_posixshm_check_open = biba_posixshm_check_open, + .mpo_posixshm_check_read = biba_posixshm_check_read, .mpo_posixshm_check_setmode = biba_posixshm_check_setmode, .mpo_posixshm_check_setowner = biba_posixshm_check_setowner, .mpo_posixshm_check_stat = biba_posixshm_check_stat, .mpo_posixshm_check_truncate = biba_posixshm_check_truncate, .mpo_posixshm_check_unlink = biba_posixshm_check_unlink, + .mpo_posixshm_check_write = biba_posixshm_check_write, .mpo_posixshm_create = biba_posixshm_create, .mpo_posixshm_destroy_label = biba_destroy_label, .mpo_posixshm_init_label = biba_init_label, diff --git a/sys/security/mac_mls/mac_mls.c b/sys/security/mac_mls/mac_mls.c index ff9084e870f8..8980f500fbb8 100644 --- a/sys/security/mac_mls/mac_mls.c +++ b/sys/security/mac_mls/mac_mls.c @@ -1650,6 +1650,24 @@ mls_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, return (0); } +static int +mls_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *shm, struct label *shmlabel) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled || !revocation_enabled) + return (0); + + subj = SLOT(active_cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + static int mls_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel, mode_t mode) @@ -1740,6 +1758,24 @@ mls_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd, return (0); } +static int +mls_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *shm, struct label *shmlabel) +{ + struct mac_mls *subj, *obj; + + if (!mls_enabled || !revocation_enabled) + return (0); + + subj = SLOT(active_cred->cr_label); + obj = SLOT(shmlabel); + + if (!mls_dominate_effective(subj, obj)) + return (EACCES); + + return (0); +} + static void mls_posixshm_create(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel) @@ -3280,11 +3316,13 @@ static struct mac_policy_ops mls_ops = .mpo_posixshm_check_mmap = mls_posixshm_check_mmap, .mpo_posixshm_check_open = mls_posixshm_check_open, + .mpo_posixshm_check_read = mls_posixshm_check_read, .mpo_posixshm_check_setmode = mls_posixshm_check_setmode, .mpo_posixshm_check_setowner = mls_posixshm_check_setowner, .mpo_posixshm_check_stat = mls_posixshm_check_stat, .mpo_posixshm_check_truncate = mls_posixshm_check_truncate, .mpo_posixshm_check_unlink = mls_posixshm_check_unlink, + .mpo_posixshm_check_write = mls_posixshm_check_write, .mpo_posixshm_create = mls_posixshm_create, .mpo_posixshm_destroy_label = mls_destroy_label, .mpo_posixshm_init_label = mls_init_label, diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c index ed25d2322383..54a67537d310 100644 --- a/sys/security/mac_stub/mac_stub.c +++ b/sys/security/mac_stub/mac_stub.c @@ -756,6 +756,14 @@ stub_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, return (0); } +static int +stub_posixshm_check_read(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *shm, struct label *shmlabel) +{ + + return (0); +} + static int stub_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel, mode_t mode) @@ -796,6 +804,14 @@ stub_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd, return (0); } +static int +stub_posixshm_check_write(struct ucred *active_cred, struct ucred *file_cred, + struct shmfd *shm, struct label *shmlabel) +{ + + return (0); +} + static void stub_posixshm_create(struct ucred *cred, struct shmfd *shmfd, struct label *shmlabel) @@ -1782,11 +1798,13 @@ static struct mac_policy_ops stub_ops = .mpo_posixshm_check_create = stub_posixshm_check_create, .mpo_posixshm_check_mmap = stub_posixshm_check_mmap, .mpo_posixshm_check_open = stub_posixshm_check_open, + .mpo_posixshm_check_read = stub_posixshm_check_read, .mpo_posixshm_check_setmode = stub_posixshm_check_setmode, .mpo_posixshm_check_setowner = stub_posixshm_check_setowner, .mpo_posixshm_check_stat = stub_posixshm_check_stat, .mpo_posixshm_check_truncate = stub_posixshm_check_truncate, .mpo_posixshm_check_unlink = stub_posixshm_check_unlink, + .mpo_posixshm_check_write = stub_posixshm_check_write, .mpo_posixshm_create = stub_posixshm_create, .mpo_posixshm_destroy_label = stub_destroy_label, .mpo_posixshm_init_label = stub_init_label, diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c index 1781798e5825..4d48dfd4bbbe 100644 --- a/sys/security/mac_test/mac_test.c +++ b/sys/security/mac_test/mac_test.c @@ -1423,6 +1423,21 @@ test_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd, return (0); } +COUNTER_DECL(posixshm_check_read); +static int +test_posixshm_check_read(struct ucred *active_cred, + struct ucred *file_cred, struct shmfd *shm, struct label *shmlabel) +{ + + LABEL_CHECK(active_cred->cr_label, MAGIC_CRED); + if (file_cred != NULL) + LABEL_CHECK(file_cred->cr_label, MAGIC_CRED); + LABEL_CHECK(shmlabel, MAGIC_POSIX_SHM); + COUNTER_INC(posixshm_check_read); + + return (0); +} + COUNTER_DECL(posixshm_check_setmode); static int test_posixshm_check_setmode(struct ucred *cred, struct shmfd *shmfd, @@ -1485,6 +1500,21 @@ test_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd, return (0); } +COUNTER_DECL(posixshm_check_write); +static int +test_posixshm_check_write(struct ucred *active_cred, + struct ucred *file_cred, struct shmfd *shm, struct label *shmlabel) +{ + + LABEL_CHECK(active_cred->cr_label, MAGIC_CRED); + if (file_cred != NULL) + LABEL_CHECK(file_cred->cr_label, MAGIC_CRED); + LABEL_CHECK(shmlabel, MAGIC_POSIX_SHM); + COUNTER_INC(posixshm_check_write); + + return (0); +} + COUNTER_DECL(posixshm_create); static void test_posixshm_create(struct ucred *cred, struct shmfd *shmfd, @@ -3114,11 +3144,13 @@ static struct mac_policy_ops test_ops = .mpo_posixshm_check_create = test_posixshm_check_create, .mpo_posixshm_check_mmap = test_posixshm_check_mmap, .mpo_posixshm_check_open = test_posixshm_check_open, + .mpo_posixshm_check_read = test_posixshm_check_read, .mpo_posixshm_check_setmode = test_posixshm_check_setmode, .mpo_posixshm_check_setowner = test_posixshm_check_setowner, .mpo_posixshm_check_stat = test_posixshm_check_stat, .mpo_posixshm_check_truncate = test_posixshm_check_truncate, .mpo_posixshm_check_unlink = test_posixshm_check_unlink, + .mpo_posixshm_check_write = test_posixshm_check_write, .mpo_posixshm_create = test_posixshm_create, .mpo_posixshm_destroy_label = test_posixshm_destroy_label, .mpo_posixshm_init_label = test_posixshm_init_label, diff --git a/sys/sys/mman.h b/sys/sys/mman.h index c5e47a0c1622..32f0e7beac2f 100644 --- a/sys/sys/mman.h +++ b/sys/sys/mman.h @@ -190,6 +190,10 @@ typedef __size_t size_t; #endif #if defined(_KERNEL) || defined(_WANT_FILE) +#include +#include +#include +#include #include struct file; @@ -214,6 +218,9 @@ struct shmfd { struct label *shm_label; /* MAC label */ const char *shm_path; + + struct rangelock shm_rl; + struct mtx shm_mtx; }; #endif