Josh Soref abce91d14b
Spelling (#12954)
* 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>
2025-07-23 15:19:00 -07:00

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;
}