github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/signalfd/signalfd.go (about)

     1  // Copyright 2019 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 signalfd provides basic signalfd file implementations.
    16  package signalfd
    17  
    18  import (
    19  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    20  	"github.com/SagerNet/gvisor/pkg/context"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    23  	"github.com/SagerNet/gvisor/pkg/sync"
    24  	"github.com/SagerNet/gvisor/pkg/syserror"
    25  	"github.com/SagerNet/gvisor/pkg/usermem"
    26  	"github.com/SagerNet/gvisor/pkg/waiter"
    27  )
    28  
    29  // SignalFileDescription implements vfs.FileDescriptionImpl for signal fds.
    30  //
    31  // +stateify savable
    32  type SignalFileDescription struct {
    33  	vfsfd vfs.FileDescription
    34  	vfs.FileDescriptionDefaultImpl
    35  	vfs.DentryMetadataFileDescriptionImpl
    36  	vfs.NoLockFD
    37  
    38  	// target is the original signal target task.
    39  	//
    40  	// The semantics here are a bit broken. Linux will always use current
    41  	// for all reads, regardless of where the signalfd originated. We can't
    42  	// do exactly that because we need to plumb the context through
    43  	// EventRegister in order to support proper blocking behavior. This
    44  	// will undoubtedly become very complicated quickly.
    45  	target *kernel.Task
    46  
    47  	// mu protects mask.
    48  	mu sync.Mutex `state:"nosave"`
    49  
    50  	// mask is the signal mask. Protected by mu.
    51  	mask linux.SignalSet
    52  }
    53  
    54  var _ vfs.FileDescriptionImpl = (*SignalFileDescription)(nil)
    55  
    56  // New creates a new signal fd.
    57  func New(vfsObj *vfs.VirtualFilesystem, target *kernel.Task, mask linux.SignalSet, flags uint32) (*vfs.FileDescription, error) {
    58  	vd := vfsObj.NewAnonVirtualDentry("[signalfd]")
    59  	defer vd.DecRef(target)
    60  	sfd := &SignalFileDescription{
    61  		target: target,
    62  		mask:   mask,
    63  	}
    64  	if err := sfd.vfsfd.Init(sfd, flags, vd.Mount(), vd.Dentry(), &vfs.FileDescriptionOptions{
    65  		UseDentryMetadata: true,
    66  		DenyPRead:         true,
    67  		DenyPWrite:        true,
    68  	}); err != nil {
    69  		return nil, err
    70  	}
    71  	return &sfd.vfsfd, nil
    72  }
    73  
    74  // Mask returns the signal mask.
    75  func (sfd *SignalFileDescription) Mask() linux.SignalSet {
    76  	sfd.mu.Lock()
    77  	defer sfd.mu.Unlock()
    78  	return sfd.mask
    79  }
    80  
    81  // SetMask sets the signal mask.
    82  func (sfd *SignalFileDescription) SetMask(mask linux.SignalSet) {
    83  	sfd.mu.Lock()
    84  	defer sfd.mu.Unlock()
    85  	sfd.mask = mask
    86  }
    87  
    88  // Read implements vfs.FileDescriptionImpl.Read.
    89  func (sfd *SignalFileDescription) Read(ctx context.Context, dst usermem.IOSequence, _ vfs.ReadOptions) (int64, error) {
    90  	// Attempt to dequeue relevant signals.
    91  	info, err := sfd.target.Sigtimedwait(sfd.Mask(), 0)
    92  	if err != nil {
    93  		// There must be no signal available.
    94  		return 0, syserror.ErrWouldBlock
    95  	}
    96  
    97  	// Copy out the signal info using the specified format.
    98  	infoNative := linux.SignalfdSiginfo{
    99  		Signo:   uint32(info.Signo),
   100  		Errno:   info.Errno,
   101  		Code:    info.Code,
   102  		PID:     uint32(info.PID()),
   103  		UID:     uint32(info.UID()),
   104  		Status:  info.Status(),
   105  		Overrun: uint32(info.Overrun()),
   106  		Addr:    info.Addr(),
   107  	}
   108  	n, err := infoNative.WriteTo(dst.Writer(ctx))
   109  	if err == usermem.ErrEndOfIOSequence {
   110  		// Partial copy-out ok.
   111  		err = nil
   112  	}
   113  	return n, err
   114  }
   115  
   116  // Readiness implements waiter.Waitable.Readiness.
   117  func (sfd *SignalFileDescription) Readiness(mask waiter.EventMask) waiter.EventMask {
   118  	sfd.mu.Lock()
   119  	defer sfd.mu.Unlock()
   120  	if mask&waiter.ReadableEvents != 0 && sfd.target.PendingSignals()&sfd.mask != 0 {
   121  		return waiter.ReadableEvents // Pending signals.
   122  	}
   123  	return 0
   124  }
   125  
   126  // EventRegister implements waiter.Waitable.EventRegister.
   127  func (sfd *SignalFileDescription) EventRegister(entry *waiter.Entry, _ waiter.EventMask) {
   128  	sfd.mu.Lock()
   129  	defer sfd.mu.Unlock()
   130  	// Register for the signal set; ignore the passed events.
   131  	sfd.target.SignalRegister(entry, waiter.EventMask(sfd.mask))
   132  }
   133  
   134  // EventUnregister implements waiter.Waitable.EventUnregister.
   135  func (sfd *SignalFileDescription) EventUnregister(entry *waiter.Entry) {
   136  	// Unregister the original entry.
   137  	sfd.target.SignalUnregister(entry)
   138  }
   139  
   140  // Release implements vfs.FileDescriptionImpl.Release.
   141  func (sfd *SignalFileDescription) Release(context.Context) {}