mirror of
https://github.com/microsoft/WSL.git
synced 2025-12-10 00:44:55 -06:00
* link: Collect WSL logs (recommended method) Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * link: Advanced Authoring Tests in C++ Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * link: CMake Documentation and Community Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * link: Collect WSL logs for networking issues Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * link: Collect WSL logs (recommended method) Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: ; otherwise, Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: a Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: access Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: accessible Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: across Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: actively Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: adapters Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: address Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: addresses Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: and Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: appropriate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: argument Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: associated Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: attach Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: available Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: beginning Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: between Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: binaries Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: bound Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: buffer Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: buffers Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: cannot Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: canonical Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: capabilities Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: case-insensitive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: case-sensitive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: certified Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: command Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: committer Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: communication Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: complains Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: configuration Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: consumed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: continue Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: converted Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: currently Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: customers Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: daemon Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: deferred Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: definitions Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: delimiter Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: delivered Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: dellink Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: derived Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: descriptor Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: destined Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: destruct Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: destructible Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: destructor Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: detach Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: differentiate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: directories Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: disassociate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: disposition Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: distribution Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: distro Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: duping Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: emitted Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: empty Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: environment Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: every time Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: exclusive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: expected Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: expire Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: explicitly Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: fall back Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: false Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: fastfail Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: filesystem Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: first Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: followed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: for Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: functionality Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: functionally Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: github Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: greater Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: guarantee Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: guaranteed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: handles Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: hangup Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: hierarchy Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: hogwarts Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: hydrated Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: icrnl Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: implementation Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: implementing Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: initialize Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: instance Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: instantiate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: instantiations Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: intentionally Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: interpret Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: interpreter Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: irreversibly Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: iteration Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: iterator Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: its Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: kernel Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: kmsg Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: knowledge Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: maximum Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: mirrored Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: msftconnecttest Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: multi Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: multiple Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: mutable Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: namespace Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: nonexistent Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: notifications Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: occurred Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: occurring Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: otherwise, Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: outstanding Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: overridden Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: partition Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: pass through Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: passthrough Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: performs Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: periodically Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: positional Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: precedence Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: preexisting Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: preferring Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: prepopulate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: previous Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: privileges Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: process Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: processes Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: programmatically Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: protection Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: provided Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: reasonable Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: receive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: received Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: red hat Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: reentrant Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: registered Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: regularly Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: relay Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: release Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: representing Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: requests Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: response Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: resurrect Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: retention Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: returned Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: security Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: semaphore Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: separate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: separator Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: service Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: set up Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: setup Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: severely Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: should Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: signal Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: similarly Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: simple Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: simplified Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: single Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: specified Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: splitting Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: standard Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: stress Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: succeed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: success Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: successfully Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: supplementary Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: synced Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: system Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: take Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: than Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: that opening Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: the Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: threadpool Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: to Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: true Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: truncate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: tunneling Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: unexpected Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: uninitialize Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: unique Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: unprivileged Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: unregistered Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: untrusted Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: upgrade Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: utility Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: validating Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: variant Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: variation Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: variations Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: verify Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: visible Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: whether Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: winget Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: worker Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: written Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: wslservice Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * format source --------- Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> Co-authored-by: Ben Hillis <benhillis@gmail.com> Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
2626 lines
84 KiB
C
2626 lines
84 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
shm.c
|
|
|
|
Abstract:
|
|
|
|
This file is a test for the system V shared memory family of system calls.
|
|
|
|
--*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/xattr.h>
|
|
#include <sys/mman.h>
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <sys/ipc.h>
|
|
#include <sys/shm.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/wait.h>
|
|
#include <grp.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#include <time.h>
|
|
#include <linux/random.h>
|
|
|
|
#if !defined(__amd64__) && !defined(__aarch64__)
|
|
|
|
#include <sys/capability.h>
|
|
|
|
#else
|
|
|
|
#include <sys/cdefs.h>
|
|
#include <linux/capability.h>
|
|
|
|
#define _LINUX_CAPABILITY_VERSION_3 0x20080522
|
|
|
|
#ifndef O_PATH
|
|
#define O_PATH 010000000
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#include "lxtcommon.h"
|
|
#include "unittests.h"
|
|
|
|
#define LXT_NAME "shm"
|
|
|
|
#define SHM_ACCESS_UID 1004
|
|
#define SHM_ACCESS_GID 1004
|
|
|
|
//
|
|
// Globals.
|
|
//
|
|
|
|
bool g_RunningOnNative = false;
|
|
bool g_VerboseShm = false;
|
|
|
|
int ShmAtAccess(PLXT_ARGS Args);
|
|
|
|
int ShmAtDtSyscall(PLXT_ARGS Args);
|
|
|
|
int ShmCtlSyscall(PLXT_ARGS Args);
|
|
|
|
int ShmGetAccess(PLXT_ARGS Args);
|
|
|
|
int ShmGetSyscall(PLXT_ARGS Args);
|
|
|
|
int ShmPidNamespace(PLXT_ARGS Args);
|
|
|
|
void ShmPrintInfo(struct shmid_ds* Stat);
|
|
|
|
void ShmPrintInfoAttach(struct shmid_ds* Stat);
|
|
|
|
static const LXT_VARIATION g_LxtVariations[] = {
|
|
{"shmget syscall", ShmGetSyscall},
|
|
{"shmget access", ShmGetAccess},
|
|
{"shmctl syscall", ShmCtlSyscall},
|
|
{"shmat / shmdt syscalls", ShmAtDtSyscall},
|
|
{"shmat access", ShmAtAccess},
|
|
{"shm pid namespace", ShmPidNamespace}};
|
|
|
|
int ShmTestEntry(int Argc, char* Argv[])
|
|
{
|
|
|
|
LXT_ARGS Args;
|
|
int Result;
|
|
|
|
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
|
|
LXT_SYNCHRONIZATION_POINT_INIT();
|
|
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
|
|
|
|
ErrorExit:
|
|
LxtUninitialize();
|
|
return 0;
|
|
}
|
|
|
|
int ShmAtAccess(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
unsigned char* Address;
|
|
struct __user_cap_data_struct CapData[2];
|
|
struct __user_cap_header_struct CapHeader;
|
|
int ChildPid;
|
|
int Id;
|
|
void* MapResult;
|
|
int Result;
|
|
|
|
Address = NULL;
|
|
ChildPid = -1;
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a shared memory region that should be unmappable by a process
|
|
// without the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and attempt to map again (should fail).
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
Address = LxtShmAt(Id, NULL, 0);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a read only memory region and verify that it is only mappable as
|
|
// read only by the owner.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0400));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and attempt to with the readonly
|
|
// flag.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, SHM_RDONLY));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Attempt to map as read / write (should fail).
|
|
//
|
|
|
|
Address = LxtShmAt(Id, NULL, 0);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Attempt to map as execute (should fail).
|
|
//
|
|
|
|
Address = LxtShmAt(Id, NULL, SHM_EXEC);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Id = -1;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a group read only memory region and verify that it is only
|
|
// mappable by members of the same group.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0040));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and attempt to with the readonly
|
|
// flag.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, SHM_RDONLY));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Attempt to map as read / write (should fail).
|
|
//
|
|
|
|
Address = LxtShmAt(Id, NULL, 0);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Attempt to map as execute (should fail).
|
|
//
|
|
|
|
Address = LxtShmAt(Id, NULL, SHM_EXEC);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create another read only memory region and verify that it is
|
|
// mappable.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0004));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Remove all group membership, drop the CAP_IPC_OWNER capability, and
|
|
// attempt to with the readonly flag.
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, SHM_RDONLY));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Attempt to map as read / write (should fail).
|
|
//
|
|
|
|
Address = LxtShmAt(Id, NULL, 0);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Attempt to map as execute (should fail).
|
|
//
|
|
|
|
Address = LxtShmAt(Id, NULL, SHM_EXEC);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a shared memory region that is write only This should be
|
|
// unmappable by processes without the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0222));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and attempt to map again (should fail).
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
Address = LxtShmAt(Id, NULL, SHM_RDONLY);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Address = LxtShmAt(Id, NULL, 0);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Attempt to map as execute (should fail).
|
|
//
|
|
|
|
Address = LxtShmAt(Id, NULL, SHM_EXEC);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a shared memory region that can only be read or written by the
|
|
// owner.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0700));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and attempt to map (should fail).
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Change the UID and verify the mapping fails.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
Address = LxtShmAt(Id, NULL, SHM_RDONLY);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Address = LxtShmAt(Id, NULL, 0);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a shared memory region that is only mappable by other.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0007));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Verify the region is mappable with CAP_IPC_OWNER.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and attempt to map again this
|
|
// should fail because the caller is still has a matching UID.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
Address = LxtShmAt(Id, NULL, SHM_RDONLY);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Change the UID and attempt to map, this should still fail because
|
|
// the caller has group ownership.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
Address = LxtShmAt(Id, NULL, SHM_RDONLY);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Change the caller GID and attempt to map, this should still fail
|
|
// because the caller has a supplementary group membership.
|
|
//
|
|
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
Address = LxtShmAt(Id, NULL, SHM_RDONLY);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Drop supplementary group membership, finally this should succeed.
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, SHM_RDONLY));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, SHM_EXEC));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, SHM_RDONLY | SHM_EXEC));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Create a shared memory region that is only mappable as read / execute.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0555));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and try to map read / write and
|
|
// read / write / execute (should fail).
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
Address = LxtShmAt(Id, NULL, 0);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Address = LxtShmAt(Id, NULL, SHM_EXEC);
|
|
if (Address != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("Unexpectedly able to shmat");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Map the region as readonly, read / execute.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, SHM_RDONLY));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, SHM_RDONLY | SHM_EXEC));
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
ErrorExit:
|
|
if (Address != NULL)
|
|
{
|
|
LxtShmDt(Address);
|
|
}
|
|
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
//
|
|
// N.B. The identifier should not be removed by any child processes.
|
|
//
|
|
|
|
if (Id != -1)
|
|
{
|
|
LxtShmCtl(Id, IPC_RMID, NULL);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int ShmAtDtSyscall(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
unsigned char* Address;
|
|
unsigned char* Address2;
|
|
int ChildPid;
|
|
int Id;
|
|
key_t Key;
|
|
void* MapResult;
|
|
struct shmid_ds ParentStat;
|
|
unsigned char* RemappedMemory;
|
|
size_t Result;
|
|
struct shmid_ds Stat;
|
|
|
|
Address = NULL;
|
|
Address2 = NULL;
|
|
ChildPid = -1;
|
|
Id = -1;
|
|
|
|
//
|
|
// (1) Create a shared memory region.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE * 3, 0));
|
|
LxtLogInfo("Id = %d", Id);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &ParentStat));
|
|
LxtCheckEqual(PAGE_SIZE * 3, ParentStat.shm_segsz, "%Iu");
|
|
LxtCheckEqual(0, ParentStat.shm_atime, "%Iu");
|
|
LxtCheckEqual(0, ParentStat.shm_dtime, "%Iu");
|
|
LxtCheckNotEqual(0, ParentStat.shm_ctime, "%Iu");
|
|
LxtCheckEqual(ParentStat.shm_nattch, 0, "%Iu");
|
|
|
|
//
|
|
// Map the shared memory region.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtLogInfo("Address = %p", Address);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &ParentStat));
|
|
ShmPrintInfoAttach(&ParentStat);
|
|
LxtCheckNotEqual(0, ParentStat.shm_atime, "%Iu");
|
|
LxtCheckEqual(0, ParentStat.shm_dtime, "%Iu");
|
|
LxtCheckEqual(ParentStat.shm_nattch, 1, "%Iu");
|
|
LxtCheckEqual(getpid(), ParentStat.shm_lpid, "%Iu");
|
|
|
|
//
|
|
// Sleep for 2 seconds then fork and verify that attach statics are
|
|
// updated correctly. The attach count and attach time should be updated
|
|
// but the last attach pid should not change.
|
|
//
|
|
|
|
sleep(2);
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 2, "%Iu");
|
|
LxtCheckEqual(ParentStat.shm_lpid, Stat.shm_lpid, "%Iu");
|
|
LxtCheckNotEqual(ParentStat.shm_atime, Stat.shm_atime, "%Iu");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckNotEqual(0, Stat.shm_dtime, "%Iu");
|
|
|
|
//
|
|
// Attempt to map the region in an area that already is mapped.
|
|
//
|
|
|
|
Address2 = LxtShmAt(Id, Address, 0);
|
|
if (Address2 != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("shmat on a used region should fail without SHM_REMAP flag %p %d", Address2, errno);
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Address2 = LxtShmAt(Id, Address + PAGE_SIZE, 0);
|
|
if (Address2 != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("shmat on a used region should fail without SHM_REMAP flag %p %d", Address2, errno);
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Address2 = LxtShmAt(Id, Address + (PAGE_SIZE * 2), 0);
|
|
if (Address2 != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("shmat on a used region should fail without SHM_REMAP flag %p %d", Address2, errno);
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (g_RunningOnNative == false)
|
|
{
|
|
LxtLogInfo("WARNING: these variations are expected to fail on native Ubuntu");
|
|
Address2 = LxtShmAt(Id, Address, SHM_REMAP);
|
|
if (Address2 != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("shmat with SHM_REMAP replacing entire region");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Address2 = LxtShmAt(Id, Address + PAGE_SIZE, SHM_REMAP);
|
|
if (Address2 != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("shmat with SHM_REMAP replacing last two pages.");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Unmap the first page in the range.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(munmap(Address, PAGE_SIZE), EINVAL);
|
|
|
|
//
|
|
// Unmap the middle page of the three-page range.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(munmap(Address + PAGE_SIZE, PAGE_SIZE), EINVAL);
|
|
|
|
//
|
|
// Unmap the last page in the range.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(munmap(Address + (2 * PAGE_SIZE), PAGE_SIZE), EINVAL);
|
|
|
|
//
|
|
// Use the remap system call to resize the region.
|
|
//
|
|
|
|
RemappedMemory = LxtMremap(Address, PAGE_SIZE * 3, PAGE_SIZE * 4, MREMAP_MAYMOVE, NULL);
|
|
|
|
if (RemappedMemory != MAP_FAILED)
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("mremap moving the region.");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Use the SHM_REMAP flag to replace the entire region.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address2 = LxtShmAt(Id, Address, SHM_REMAP));
|
|
LxtCheckEqual(Address, Address2, "%p");
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
LxtCheckErrnoFailure(LxtShmDt(Address), EINVAL);
|
|
|
|
//
|
|
// Use the SHM_REMAP flag to replace the last two pages of the original
|
|
// region.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, Address, 0));
|
|
LxtCheckMapErrno(Address2 = LxtShmAt(Id, Address + PAGE_SIZE, SHM_REMAP));
|
|
LxtCheckEqual(Address + PAGE_SIZE, Address2, "%p");
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 2, "%Iu");
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckErrno(LxtShmDt(Address2));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
LxtCheckErrnoFailure(LxtShmDt(Address), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmDt(Address2), EINVAL);
|
|
Address = NULL;
|
|
Address2 = NULL;
|
|
|
|
//
|
|
// Unmap the middle page of the three-page range to split the region,
|
|
// this should increment the attach count.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(munmap(Address + PAGE_SIZE, PAGE_SIZE));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 2, "%Iu");
|
|
LxtCheckNotEqual(0, Stat.shm_dtime, "%Iu");
|
|
|
|
//
|
|
// Unmap the last page in the range.
|
|
//
|
|
|
|
LxtCheckErrno(munmap(Address + (2 * PAGE_SIZE), PAGE_SIZE));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
|
|
//
|
|
// Use detach to clear the range.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
|
|
//
|
|
// (2) Map the region again. Unmap the middle page of the three-page range.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtLogInfo("Address = %p", Address);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckErrno(munmap(Address + PAGE_SIZE, PAGE_SIZE));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 2, "%Iu");
|
|
|
|
//
|
|
// Use shmdt to remove both remaining mapped regions, this should unmap
|
|
// both attached regions.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
|
|
//
|
|
// (3) Use the remap system call to resize the region.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtLogInfo("Address = %p", Address);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckMapErrno(RemappedMemory = LxtMremap(Address, PAGE_SIZE * 3, PAGE_SIZE * 4, MREMAP_MAYMOVE, NULL));
|
|
|
|
LxtLogInfo("RemappedMemory = %p", RemappedMemory);
|
|
|
|
//
|
|
// If the address changed, attempt to remap the old address.
|
|
//
|
|
|
|
if (Address != RemappedMemory)
|
|
{
|
|
LxtCheckErrnoFailure(LxtShmDt(Address), EINVAL);
|
|
Address = RemappedMemory;
|
|
}
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
|
|
//
|
|
// Unmap the middle two pages in the range.
|
|
//
|
|
|
|
LxtCheckErrno(munmap(Address + PAGE_SIZE, (2 * PAGE_SIZE)));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 2, "%Iu");
|
|
|
|
//
|
|
// Unmap the first page in the range.
|
|
//
|
|
|
|
LxtCheckErrno(munmap(Address, PAGE_SIZE));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
|
|
//
|
|
// Use shmdt to remove the remaining region (the last page in the range).
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
|
|
//
|
|
// (4) Map the region again. Use the mremap system call to shrink the
|
|
// region and validate that the global shared memory region remains the
|
|
// same size.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtLogInfo("Address = %p", Address);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckEqual(Stat.shm_segsz, (PAGE_SIZE * 3), "%Iu");
|
|
LxtCheckMapErrno(RemappedMemory = LxtMremap(Address, PAGE_SIZE * 3, PAGE_SIZE, 0, NULL));
|
|
|
|
LxtLogInfo("RemappedMemory = %p", RemappedMemory);
|
|
LxtCheckEqual(Address, RemappedMemory, "%p");
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckEqual(Stat.shm_segsz, PAGE_SIZE * 3, "%Iu");
|
|
|
|
//
|
|
// Use shmdt to remove the region.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
|
|
//
|
|
// (5) Map the region twice.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtLogInfo("Address = %p", Address);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
|
|
LxtCheckMapErrno(Address2 = LxtShmAt(Id, NULL, 0));
|
|
LxtLogInfo("Address2 = %p", Address2);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 2, "%Iu");
|
|
|
|
//
|
|
// Ensure the shared memory region were mapped to different locations and
|
|
// detach both.
|
|
//
|
|
|
|
LxtCheckNotEqual(Address, Address2, "%p");
|
|
LxtCheckErrno(LxtShmDt(Address2));
|
|
Address2 = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
|
|
//
|
|
// (6) Map the region, delete the region, and validate that the region is
|
|
// still able to be mapped.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
|
|
//
|
|
// Delete the region again (should succeed).
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
Address[0] = 'a';
|
|
LxtCheckMapErrno(Address2 = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
Address2[0] = 'a';
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 2, "%Iu");
|
|
|
|
//
|
|
// Detach both mapped regions.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfoAttach(&Stat);
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
LxtCheckErrno(LxtShmDt(Address2));
|
|
Address2 = NULL;
|
|
|
|
//
|
|
// The region should be deleted at this point to the shmctl should fail.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_STAT, &Stat), EINVAL);
|
|
Id = -1;
|
|
|
|
//
|
|
// (7) Delete the shared memory region and attempt to attach it afterwards.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE * 3, 0));
|
|
LxtLogInfo("Id = %d", Id);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Address = LxtShmAt(Id, NULL, 0);
|
|
if ((Address != MAP_FAILED) && (errno != EINVAL))
|
|
{
|
|
Result = LXT_RESULT_FAILURE;
|
|
LxtLogError("unexpectedly able to attach deleted memory region %p, %d", Address, errno);
|
|
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Attempt to stat the deleted region.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_STAT, &Stat), EINVAL);
|
|
Id = -1;
|
|
|
|
//
|
|
// (8) Use mremap to move the last page to a new location.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE * 3, 0));
|
|
LxtLogInfo("Id = %d", Id);
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtLogInfo("Address = %p", Address);
|
|
LxtCheckMapErrno(Address2 = LxtMremap(Address + (2 * PAGE_SIZE), PAGE_SIZE, PAGE_SIZE * 4, MREMAP_MAYMOVE, NULL));
|
|
|
|
LxtLogInfo("Address2 = %p", Address2);
|
|
LxtCheckNotEqual(Address + (2 * PAGE_SIZE), Address2, "%p");
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 2, "%Iu");
|
|
|
|
//
|
|
// Detach the original address and validate the second region remains.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmDt(Address));
|
|
Address = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
|
|
//
|
|
// Ensure that shmdt does not work for the new address.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(LxtShmDt(Address2), EINVAL);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 1, "%Iu");
|
|
|
|
//
|
|
// Call shmdt on what would have been the start of the new region.
|
|
//
|
|
// N.B. This functions like a new mapping of the memory where the first two
|
|
// pages have been unmapped.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmDt(Address2 - (2 * PAGE_SIZE)));
|
|
Address2 = NULL;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_nattch, 0, "%Iu");
|
|
|
|
ErrorExit:
|
|
if (Address != NULL)
|
|
{
|
|
LxtShmDt(Address);
|
|
}
|
|
|
|
if (Address2 != NULL)
|
|
{
|
|
LxtShmDt(Address2);
|
|
}
|
|
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
if (Id != -1)
|
|
{
|
|
LxtShmCtl(Id, IPC_RMID, NULL);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int ShmGetAccess(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
struct __user_cap_data_struct CapData[2];
|
|
struct __user_cap_header_struct CapHeader;
|
|
int ChildPid;
|
|
int Id;
|
|
key_t Key;
|
|
int Mode;
|
|
int Result;
|
|
|
|
ChildPid = -1;
|
|
Id = -1;
|
|
|
|
LxtCheckErrno(LxtGetrandom(&Key, sizeof(Key), 0));
|
|
LxtLogInfo("Key = %u", Key);
|
|
|
|
//
|
|
// Create a shared memory region with a mode of all zeros.
|
|
//
|
|
|
|
Mode = 0000;
|
|
LxtCheckErrno(Id = LxtShmGet(Key, PAGE_SIZE, (IPC_CREAT | IPC_EXCL | Mode)));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// First attempt with the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the UID.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the GID.
|
|
//
|
|
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Drop supplementary group membership.
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a shared memory region with a user read / write / execute mode.
|
|
//
|
|
|
|
Mode = 0700;
|
|
LxtCheckErrno(Id = LxtShmGet(Key, PAGE_SIZE, (IPC_CREAT | IPC_EXCL | Mode)));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// First attempt with the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0700), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0070), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0007), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0124), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the UID.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the GID.
|
|
//
|
|
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Drop supplementary group membership.
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a shared memory region with a group read / write / execute mode.
|
|
//
|
|
|
|
Mode = 0070;
|
|
LxtCheckErrno(Id = LxtShmGet(Key, PAGE_SIZE, (IPC_CREAT | IPC_EXCL | Mode)));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// First attempt with the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the UID (group still matches so this should succeed).
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0700), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0070), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0007), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0124), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the GID (callers still has supplementary group membership so
|
|
// this should succeed).
|
|
//
|
|
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0700), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0070), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0007), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0124), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Drop supplementary group membership.
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a shared memory region with a other read / write / execute mode.
|
|
//
|
|
|
|
Mode = 0007;
|
|
LxtCheckErrno(Id = LxtShmGet(Key, PAGE_SIZE, (IPC_CREAT | IPC_EXCL | Mode)));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// First attempt with the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the UID.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the GID (callers still has supplementary group membership so
|
|
// this should succeed).
|
|
//
|
|
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Drop supplementary group membership (this should succeed).
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0700), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0070), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0007), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0124), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a shared memory region with a other read / write mode.
|
|
//
|
|
|
|
Mode = 0006;
|
|
LxtCheckErrno(Id = LxtShmGet(Key, PAGE_SIZE, (IPC_CREAT | IPC_EXCL | Mode)));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// First attempt with the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0006), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0004), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0002), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0001), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the UID.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0006), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0004), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0002), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0001), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Change the GID (callers still has supplementary group membership so
|
|
// this should succeed).
|
|
//
|
|
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0006), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0004), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0002), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0001), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
|
|
//
|
|
// Drop supplementary group membership (this should succeed).
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0700), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0070), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0007), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0124), EACCES);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0666), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0600), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0060), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0006), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0024), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0424), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0024), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0000), "%Iu");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
Id = -1;
|
|
|
|
ErrorExit:
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
//
|
|
// N.B. The identifier should not be removed by any child processes.
|
|
//
|
|
|
|
if (Id != -1)
|
|
{
|
|
LxtShmCtl(Id, IPC_RMID, NULL);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int ShmGetSyscall(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
struct __user_cap_data_struct CapData[2];
|
|
struct __user_cap_header_struct CapHeader;
|
|
int ChildPid;
|
|
int Id;
|
|
key_t Key;
|
|
int Mode;
|
|
size_t Result;
|
|
struct shmid_ds Stat;
|
|
time_t Time;
|
|
|
|
ChildPid = -1;
|
|
Id = -1;
|
|
|
|
//
|
|
// Create a key, verify that creating the key with the IPC_EXCL flag fails.
|
|
//
|
|
|
|
Mode = 0000;
|
|
LxtLogInfo("Mode %o", Mode);
|
|
LxtCheckErrno(LxtGetrandom(&Key, sizeof(Key), 0));
|
|
LxtLogInfo("Key = %u", Key);
|
|
LxtCheckErrno(Id = LxtShmGet(Key, PAGE_SIZE, (IPC_CREAT | IPC_EXCL | Mode)));
|
|
LxtLogInfo("Id = %d", Id);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
ShmPrintInfo(&Stat);
|
|
LxtCheckEqual(Key, Stat.shm_perm.__key, "%Iu");
|
|
LxtCheckEqual(PAGE_SIZE, Stat.shm_segsz, "%Iu");
|
|
LxtCheckEqual(getpid(), Stat.shm_cpid, "%Iu");
|
|
LxtCheckEqual(0, Stat.shm_lpid, "%Iu");
|
|
LxtCheckEqual(0, Stat.shm_atime, "%Iu");
|
|
LxtCheckEqual(0, Stat.shm_dtime, "%Iu");
|
|
LxtCheckNotEqual(0, Stat.shm_ctime, "%Iu");
|
|
LxtCheckEqual(Mode, Stat.shm_perm.mode, "%o");
|
|
LxtCheckEqual(getuid(), Stat.shm_perm.cuid, "%d");
|
|
LxtCheckEqual(getuid(), Stat.shm_perm.uid, "%d");
|
|
LxtCheckEqual(getgid(), Stat.shm_perm.cgid, "%d");
|
|
LxtCheckEqual(getgid(), Stat.shm_perm.gid, "%d");
|
|
|
|
//
|
|
// shmget with IPC_CREAT or IPC_EXCL when the region already exists.
|
|
//
|
|
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, IPC_CREAT), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, IPC_EXCL), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0), "%Iu");
|
|
|
|
//
|
|
// Create a child with a different uid and gid that does not have the
|
|
// IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
|
|
//
|
|
// These should succeed because the child still has the IPC_OWNER cap.
|
|
//
|
|
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, IPC_CREAT), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, IPC_EXCL), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0777), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0666), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0600), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0060), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0006), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0), "%Iu");
|
|
|
|
//
|
|
// Drop all group membership and the CAP_IPC_OWNER capability and
|
|
// attempt to call shmget with unmatching mode bits.
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0777), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0666), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0600), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0060), EACCES);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, 0006), EACCES);
|
|
|
|
//
|
|
// Use the same permission as before, these should succeed.
|
|
//
|
|
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, IPC_CREAT), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, IPC_EXCL), "%Iu");
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, 0), "%Iu");
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// shmget with size = 0 should succeed.
|
|
//
|
|
|
|
LxtCheckEqual(Id, LxtShmGet(Key, 0, 0), "%Iu");
|
|
|
|
//
|
|
// Invalid parameter variations.
|
|
//
|
|
|
|
//
|
|
// shmget with IPC_CREAT | IPC_EXCL when the region already exists, should
|
|
// succeed with only IPC_EXCL.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, (IPC_CREAT | IPC_EXCL)), EEXIST);
|
|
|
|
//
|
|
// shmget with a known key and a size that does not match.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, (PAGE_SIZE * 2), 0), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE + 1, 0), EINVAL);
|
|
|
|
//
|
|
// N.B. There appears to be no error checking for invalid flags, only the
|
|
// presence of valid flags.
|
|
//
|
|
// -1 includes the IPC_EXCL flag so this should return EEXIST.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(LxtShmGet(Key, PAGE_SIZE, -1), EEXIST);
|
|
LxtCheckEqual(Id, LxtShmGet(Key, PAGE_SIZE, (-1 & ~IPC_EXCL)), "%Iu");
|
|
|
|
//
|
|
// Delete the region and create a new one with a size of one byte.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, &Stat));
|
|
Id = -1;
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, 1, 0));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(1, Stat.shm_segsz, "%Iu");
|
|
|
|
//
|
|
// Delete the region and create a new region with a size of zero bytes
|
|
// (should fail).
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, &Stat));
|
|
Id = -1;
|
|
LxtCheckErrnoFailure(Id = LxtShmGet(IPC_PRIVATE, 0, 0), EINVAL);
|
|
|
|
ErrorExit:
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
if (Id != -1)
|
|
{
|
|
LxtShmCtl(Id, IPC_RMID, &Stat);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int ShmCtlSyscall(PLXT_ARGS Args)
|
|
|
|
{
|
|
|
|
struct __user_cap_data_struct CapData[2];
|
|
struct __user_cap_header_struct CapHeader;
|
|
int ChildPid;
|
|
int Id;
|
|
struct shminfo IpcInfo;
|
|
key_t Key;
|
|
struct shmid_ds OldStat;
|
|
int RandomId;
|
|
size_t Result;
|
|
struct shm_info ShmInfo;
|
|
struct shmid_ds Stat = {0};
|
|
|
|
Id = -1;
|
|
|
|
//
|
|
// Test permissions for the IPC_STAT.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0));
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// First attempt with the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and verify that the region cannot
|
|
// be queried.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_STAT, &Stat), EACCES);
|
|
|
|
//
|
|
// Create a no access shared memory region and verify that it cannot be
|
|
// queried without the CAP_IPC_OWNER (even by its owner).
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0));
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_STAT, &Stat), EACCES);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
|
|
//
|
|
// Create a write only shared memory region and verify that it cannot be
|
|
// queried without the CAP_IPC_OWNER (even by its owner).
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0200));
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_STAT, &Stat), EACCES);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
|
|
//
|
|
// Create a read only shared memory region and verify that it can be
|
|
// queried.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0400));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Test permissions for IPC_SET.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// First attempt with the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and verify that IPC_SET can still
|
|
// be called by the owner.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Change the GID.
|
|
//
|
|
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Drop supplementary group membership.
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Change the UID (this should fail).
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_SET, NULL), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_SET, &Stat), EPERM);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Test permissions for IPC_SET.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// First attempt with the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability and verify that IPC_SET can still
|
|
// be called by the creator and owner.
|
|
//
|
|
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Change the owner UID.
|
|
//
|
|
|
|
Stat.shm_perm.uid = SHM_ACCESS_UID;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Change the GID.
|
|
//
|
|
|
|
LxtCheckErrno(setgid(SHM_ACCESS_GID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Drop supplementary group membership.
|
|
//
|
|
|
|
LxtCheckErrno(Result = setgroups(0, NULL));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Change the UID to match (this should succeed).
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// IPC_STAT should still fail.
|
|
//
|
|
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_STAT, &Stat), EACCES);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Reset the region's UID.
|
|
//
|
|
|
|
Stat.shm_perm.uid = getuid();
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Test permissions for SHM_LOCK / SHM_UNLOCK.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Drop the CAP_IPC_LOCK capability.
|
|
//
|
|
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
LxtCheckErrno(LxtCapGet(&CapHeader, CapData)) LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
CapData[CAP_TO_INDEX(CAP_IPC_LOCK)].permitted &= ~CAP_TO_MASK(CAP_IPC_LOCK);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
|
|
//
|
|
// Change the UID and verify SHM_LOCK and SHM_UNLOCK fail.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, SHM_LOCK, NULL), EPERM);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, SHM_UNLOCK, NULL), EPERM);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Test permissions for IPC_RMID.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
|
|
//
|
|
// Change the UID and verify IPC_RMID fails.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_RMID, NULL), EPERM);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Verify IPC_RMID can be called by the memory region's owner.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
//
|
|
// Drop the CAP_IPC_OWNER capability.
|
|
//
|
|
|
|
LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
|
|
memset(&CapData, 0, sizeof(CapData));
|
|
memset(&CapHeader, 0, sizeof(CapHeader));
|
|
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
|
CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
|
CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
|
CapData[0].effective = CapData[0].permitted;
|
|
CapData[1].effective = CapData[1].permitted;
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
|
|
//
|
|
// Change the owner UID.
|
|
//
|
|
|
|
Stat.shm_perm.uid = SHM_ACCESS_UID;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
|
|
//
|
|
// Change the caller's UID to match.
|
|
//
|
|
|
|
LxtCheckErrno(setuid(SHM_ACCESS_UID));
|
|
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_RMID, NULL));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Wait for the child to exit.
|
|
//
|
|
|
|
LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
|
|
|
|
//
|
|
// Create a new shared memory region since the previous was just deleted.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0));
|
|
|
|
//
|
|
// Verify IPC_INFO.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_INFO, &IpcInfo));
|
|
LxtCheckErrno(LxtShmCtl(0, IPC_INFO, &IpcInfo));
|
|
LxtLogInfo("shminfo.shmmax %Iu", IpcInfo.shmmax);
|
|
LxtLogInfo("shminfo.shmmin %Iu", IpcInfo.shmmin);
|
|
LxtLogInfo("shminfo.shmmni %Iu", IpcInfo.shmmni);
|
|
LxtLogInfo("shminfo.shmseg %Iu", IpcInfo.shmseg);
|
|
LxtLogInfo("shminfo.shmall %Iu", IpcInfo.shmall);
|
|
LxtCheckEqual(IpcInfo.shmmin, 1, "%Iu");
|
|
|
|
//
|
|
// Verify SHM_INFO.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, SHM_INFO, &ShmInfo));
|
|
LxtCheckErrno(LxtShmCtl(0, SHM_INFO, &ShmInfo));
|
|
LxtLogInfo("shm_info.used_ids %Iu", ShmInfo.used_ids);
|
|
LxtLogInfo("shm_info.shm_tot %Iu", ShmInfo.shm_tot);
|
|
LxtLogInfo("shm_info.shm_rss %Iu", ShmInfo.shm_rss);
|
|
LxtLogInfo("shm_info.shm_swp %Iu", ShmInfo.shm_swp);
|
|
LxtLogInfo("shm_info.swap_attempts %Iu", ShmInfo.swap_attempts);
|
|
LxtLogInfo("shm_info.swap_successes %Iu", ShmInfo.swap_successes);
|
|
LxtCheckNotEqual(ShmInfo.used_ids, 0, "%Iu");
|
|
|
|
//
|
|
// Verify SHM_LOCK and SHM_UNLOCK. The locked state is boolean (there is
|
|
// no count for locked / unlocked).
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, SHM_LOCK, NULL));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(SHM_LOCKED, Stat.shm_perm.mode & SHM_LOCKED, "%o");
|
|
LxtCheckErrno(LxtShmCtl(Id, SHM_LOCK, NULL));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(SHM_LOCKED, Stat.shm_perm.mode & SHM_LOCKED, "%o");
|
|
LxtCheckErrno(LxtShmCtl(Id, SHM_UNLOCK, NULL));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(0, Stat.shm_perm.mode & SHM_LOCKED, "%o");
|
|
LxtCheckErrno(LxtShmCtl(Id, SHM_UNLOCK, NULL));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(0, Stat.shm_perm.mode & SHM_LOCKED, "%o");
|
|
|
|
//
|
|
// Invalid parameter variations.
|
|
//
|
|
|
|
//
|
|
// Ensure IPC_SET cannot set invalid mode bits (they are silently ignored).
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
Stat.shm_perm.mode = -1;
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_SET, &Stat));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_perm.mode, 0777, "%o");
|
|
|
|
//
|
|
// Ensure the uid and gid cannot be set to -1.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &OldStat));
|
|
Stat = OldStat;
|
|
Stat.shm_perm.uid = -1;
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_SET, &Stat), EINVAL);
|
|
Stat = OldStat;
|
|
Stat.shm_perm.gid = -1;
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_SET, &Stat), EINVAL);
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(Stat.shm_perm.uid, OldStat.shm_perm.uid, "%d");
|
|
LxtCheckEqual(Stat.shm_perm.gid, OldStat.shm_perm.gid, "%d");
|
|
|
|
LxtCheckErrnoFailure(LxtShmCtl(-1, IPC_STAT, NULL), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_STAT, NULL), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_STAT, -1), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(-1, IPC_SET, NULL), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_SET, NULL), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_SET, -1), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(-1, IPC_INFO, NULL), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_INFO, NULL), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, IPC_INFO, -1), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(-1, SHM_INFO, NULL), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, SHM_INFO, NULL), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(Id, SHM_INFO, -1), EFAULT);
|
|
LxtCheckErrnoFailure(LxtShmCtl(-1, SHM_LOCK, NULL), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(-1, SHM_UNLOCK, NULL), EINVAL);
|
|
|
|
//
|
|
// Generate an ID that does not refer to a valid memory region and attempt
|
|
// operations on the nonexistent region.
|
|
//
|
|
|
|
do
|
|
{
|
|
LxtCheckErrno(LxtGetrandom(&RandomId, sizeof(RandomId), 0));
|
|
Result = LxtShmCtl(RandomId, IPC_STAT, &Stat);
|
|
} while ((Result == 0) && (errno != EINVAL));
|
|
|
|
LxtCheckErrnoFailure(LxtShmCtl(RandomId, IPC_RMID, NULL), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(RandomId, IPC_STAT, &Stat), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(RandomId, IPC_SET, &Stat), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(RandomId, SHM_LOCK, NULL), EINVAL);
|
|
LxtCheckErrnoFailure(LxtShmCtl(RandomId, SHM_UNLOCK, NULL), EINVAL);
|
|
|
|
ErrorExit:
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
if (Id != -1)
|
|
{
|
|
LxtShmCtl(Id, IPC_RMID, NULL);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int ShmPidNamespaceWork(void)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tests the behavior of System V shared memory across IPC
|
|
namespaces. A child threadgroup is forked into a new IPC namespace,
|
|
|
|
|
|
and the parent and
|
|
child communicate across a unix socket connection. Each side queries the
|
|
credentials of the other side via SO_PEERCRED and ancillary messages and
|
|
validates that the appropriate credentials are returned.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
0 on success, -1 on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
void* Address;
|
|
void* Address2;
|
|
pid_t ChildPid = 0;
|
|
int Id;
|
|
void* MapResult;
|
|
pid_t ParentPid;
|
|
struct shmid_ds ParentStat;
|
|
int Result;
|
|
struct shmid_ds Stat;
|
|
int Status;
|
|
|
|
Address = NULL;
|
|
Address2 = NULL;
|
|
Id = -1;
|
|
|
|
LXT_SYNCHRONIZATION_POINT_START();
|
|
|
|
//
|
|
// Create and map a shared memory region.
|
|
//
|
|
|
|
LxtCheckErrno(Id = LxtShmGet(IPC_PRIVATE, PAGE_SIZE, 0));
|
|
LxtCheckMapErrno(Address = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &ParentStat));
|
|
|
|
//
|
|
// Unshare the PID namespace used for children.
|
|
//
|
|
|
|
LxtLogInfo("Unsharing CLONE_NEWPID");
|
|
LxtCheckErrno(unshare(CLONE_NEWPID));
|
|
|
|
//
|
|
// Fork a child that will exist in a new IPC namespace.
|
|
//
|
|
|
|
ParentPid = getpid();
|
|
LxtLogInfo("ParentPid %d", ParentPid);
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
|
|
LxtLogInfo("Child's view of ChildPid %d", getpid());
|
|
|
|
//
|
|
// Attach the shared segment.
|
|
//
|
|
|
|
LxtCheckMapErrno(Address2 = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(getpid(), Stat.shm_lpid, "%d");
|
|
|
|
LXT_SYNCHRONIZATION_POINT();
|
|
|
|
//
|
|
// Wait for the parent to query credentials.
|
|
//
|
|
|
|
LXT_SYNCHRONIZATION_POINT();
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(ParentPid, Stat.shm_lpid, "%d");
|
|
}
|
|
else
|
|
{
|
|
|
|
LxtLogInfo("Parent's view of ChildPid %d", ChildPid);
|
|
|
|
//
|
|
// Wait for the child to attach.
|
|
//
|
|
|
|
LXT_SYNCHRONIZATION_POINT();
|
|
|
|
//
|
|
// Query the last attach pid (should NOT match ChildPid) and create
|
|
// a new mapping.
|
|
//
|
|
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckNotEqual(ChildPid, Stat.shm_lpid, "%d");
|
|
LxtCheckMapErrno(Address2 = LxtShmAt(Id, NULL, 0));
|
|
LxtCheckErrno(LxtShmCtl(Id, IPC_STAT, &Stat));
|
|
LxtCheckEqual(getpid(), Stat.shm_lpid, "%d");
|
|
|
|
LXT_SYNCHRONIZATION_POINT();
|
|
}
|
|
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
LXT_SYNCHRONIZATION_POINT_END();
|
|
if (Address != NULL)
|
|
{
|
|
LxtShmDt(Address);
|
|
}
|
|
|
|
if (Address2 != NULL)
|
|
{
|
|
LxtShmDt(Address2);
|
|
}
|
|
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(Result);
|
|
}
|
|
|
|
if (Id != -1)
|
|
{
|
|
LxtShmCtl(Id, IPC_RMID, NULL);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
int ShmPidNamespace(PLXT_ARGS Args)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tests the behavior of System V shared memory across IPC
|
|
namespaces.
|
|
|
|
Arguments:
|
|
|
|
Args - Supplies the command line arguments.
|
|
|
|
Return Value:
|
|
|
|
0 on success, -1 on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
pid_t ChildPid;
|
|
int Result;
|
|
|
|
//
|
|
// Fork into a new parent so that the existing threadgroup does not have its
|
|
// IPC namespaces altered for later tests.
|
|
//
|
|
|
|
LxtCheckErrno(ChildPid = fork());
|
|
if (ChildPid == 0)
|
|
{
|
|
_exit(ShmPidNamespaceWork());
|
|
}
|
|
|
|
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
|
|
Result = LXT_RESULT_SUCCESS;
|
|
|
|
ErrorExit:
|
|
return Result;
|
|
}
|
|
|
|
void ShmPrintInfo(struct shmid_ds* Stat)
|
|
|
|
{
|
|
|
|
if (g_VerboseShm == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LxtLogInfo("shm_perm.__key %u", Stat->shm_perm.__key);
|
|
LxtLogInfo("shm_perm.uid %u", Stat->shm_perm.uid);
|
|
LxtLogInfo("shm_perm.gid %u", Stat->shm_perm.gid);
|
|
LxtLogInfo("shm_perm.cuid %u", Stat->shm_perm.cuid);
|
|
LxtLogInfo("shm_perm.cgid %u", Stat->shm_perm.cgid);
|
|
LxtLogInfo("shm_perm.mode %o", Stat->shm_perm.mode);
|
|
LxtLogInfo("shm_perm.__seq %d", Stat->shm_perm.__seq);
|
|
LxtLogInfo("shm_segsz %Iu", Stat->shm_segsz);
|
|
LxtLogInfo("shm_atime %Iu", Stat->shm_atime);
|
|
LxtLogInfo("shm_dtime %Iu", Stat->shm_dtime);
|
|
LxtLogInfo("shm_ctime %Iu", Stat->shm_ctime);
|
|
LxtLogInfo("shm_cpid %Iu", Stat->shm_cpid);
|
|
LxtLogInfo("shm_lpid %Iu", Stat->shm_lpid);
|
|
LxtLogInfo("shm_nattch %Iu", Stat->shm_nattch);
|
|
return;
|
|
}
|
|
|
|
void ShmPrintInfoAttach(struct shmid_ds* Stat)
|
|
|
|
{
|
|
|
|
if (g_VerboseShm == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LxtLogInfo("shm_segsz %Iu", Stat->shm_segsz);
|
|
LxtLogInfo("shm_atime %Iu", Stat->shm_atime);
|
|
LxtLogInfo("shm_dtime %Iu", Stat->shm_dtime);
|
|
LxtLogInfo("shm_ctime %Iu", Stat->shm_ctime);
|
|
LxtLogInfo("shm_cpid %Iu", Stat->shm_cpid);
|
|
LxtLogInfo("shm_lpid %Iu", Stat->shm_lpid);
|
|
LxtLogInfo("shm_nattch %Iu", Stat->shm_nattch);
|
|
return;
|
|
}
|