github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/sys_shm.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package linux
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    20  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/shm"
    23  )
    24  
    25  // Shmget implements shmget(2).
    26  func Shmget(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    27  	key := shm.Key(args[0].Int())
    28  	size := uint64(args[1].SizeT())
    29  	flag := args[2].Int()
    30  
    31  	private := key == linux.IPC_PRIVATE
    32  	create := flag&linux.IPC_CREAT == linux.IPC_CREAT
    33  	exclusive := flag&linux.IPC_EXCL == linux.IPC_EXCL
    34  	mode := linux.FileMode(flag & 0777)
    35  
    36  	pid := int32(t.ThreadGroup().ID())
    37  	r := t.IPCNamespace().ShmRegistry()
    38  	segment, err := r.FindOrCreate(t, pid, key, size, mode, private, create, exclusive)
    39  	if err != nil {
    40  		return 0, nil, err
    41  	}
    42  	defer segment.DecRef(t)
    43  	return uintptr(segment.ID), nil, nil
    44  }
    45  
    46  // findSegment retrives a shm segment by the given id.
    47  //
    48  // findSegment returns a reference on Shm.
    49  func findSegment(t *kernel.Task, id shm.ID) (*shm.Shm, error) {
    50  	r := t.IPCNamespace().ShmRegistry()
    51  	segment := r.FindByID(id)
    52  	if segment == nil {
    53  		// No segment with provided id.
    54  		return nil, linuxerr.EINVAL
    55  	}
    56  	return segment, nil
    57  }
    58  
    59  // Shmat implements shmat(2).
    60  func Shmat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    61  	id := shm.ID(args[0].Int())
    62  	addr := args[1].Pointer()
    63  	flag := args[2].Int()
    64  
    65  	segment, err := findSegment(t, id)
    66  	if err != nil {
    67  		return 0, nil, linuxerr.EINVAL
    68  	}
    69  	defer segment.DecRef(t)
    70  
    71  	opts, err := segment.ConfigureAttach(t, addr, shm.AttachOpts{
    72  		Execute:  flag&linux.SHM_EXEC == linux.SHM_EXEC,
    73  		Readonly: flag&linux.SHM_RDONLY == linux.SHM_RDONLY,
    74  		Remap:    flag&linux.SHM_REMAP == linux.SHM_REMAP,
    75  	})
    76  	if err != nil {
    77  		return 0, nil, err
    78  	}
    79  	addr, err = t.MemoryManager().MMap(t, opts)
    80  	return uintptr(addr), nil, err
    81  }
    82  
    83  // Shmdt implements shmdt(2).
    84  func Shmdt(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    85  	addr := args[0].Pointer()
    86  	err := t.MemoryManager().DetachShm(t, addr)
    87  	return 0, nil, err
    88  }
    89  
    90  // Shmctl implements shmctl(2).
    91  func Shmctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    92  	id := shm.ID(args[0].Int())
    93  	cmd := args[1].Int()
    94  	buf := args[2].Pointer()
    95  
    96  	r := t.IPCNamespace().ShmRegistry()
    97  
    98  	switch cmd {
    99  	case linux.SHM_STAT:
   100  		// Technically, we should be treating id as "an index into the kernel's
   101  		// internal array that maintains information about all shared memory
   102  		// segments on the system". Since we don't track segments in an array,
   103  		// we'll just pretend the shmid is the index and do the same thing as
   104  		// IPC_STAT. Linux also uses the index as the shmid.
   105  		fallthrough
   106  	case linux.IPC_STAT:
   107  		segment, err := findSegment(t, id)
   108  		if err != nil {
   109  			return 0, nil, linuxerr.EINVAL
   110  		}
   111  		defer segment.DecRef(t)
   112  
   113  		stat, err := segment.IPCStat(t)
   114  		if err == nil {
   115  			_, err = stat.CopyOut(t, buf)
   116  		}
   117  		return 0, nil, err
   118  
   119  	case linux.IPC_INFO:
   120  		params := r.IPCInfo()
   121  		_, err := params.CopyOut(t, buf)
   122  		return 0, nil, err
   123  
   124  	case linux.SHM_INFO:
   125  		info := r.ShmInfo()
   126  		_, err := info.CopyOut(t, buf)
   127  		return 0, nil, err
   128  	}
   129  
   130  	// Remaining commands refer to a specific segment.
   131  	segment, err := findSegment(t, id)
   132  	if err != nil {
   133  		return 0, nil, linuxerr.EINVAL
   134  	}
   135  	defer segment.DecRef(t)
   136  
   137  	switch cmd {
   138  	case linux.IPC_SET:
   139  		var ds linux.ShmidDS
   140  		if _, err = ds.CopyIn(t, buf); err != nil {
   141  			return 0, nil, err
   142  		}
   143  		err := segment.Set(t, &ds)
   144  		return 0, nil, err
   145  
   146  	case linux.IPC_RMID:
   147  		segment.MarkDestroyed(t)
   148  		return 0, nil, nil
   149  
   150  	case linux.SHM_LOCK, linux.SHM_UNLOCK:
   151  		// We currently do not support memory locking anywhere.
   152  		// mlock(2)/munlock(2) are currently stubbed out as no-ops so do the
   153  		// same here.
   154  		t.Kernel().EmitUnimplementedEvent(t)
   155  		return 0, nil, nil
   156  
   157  	default:
   158  		return 0, nil, linuxerr.EINVAL
   159  	}
   160  }