github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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/nicocha30/gvisor-ligolo/pkg/abi/linux"
    20  	"github.com/nicocha30/gvisor-ligolo/pkg/context"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/vfs"
    24  	"github.com/nicocha30/gvisor-ligolo/pkg/sync"
    25  	"github.com/nicocha30/gvisor-ligolo/pkg/usermem"
    26  	"github.com/nicocha30/gvisor-ligolo/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  	vfs.NoAsyncEventFD
    38  
    39  	// target is the original signal target task.
    40  	//
    41  	// The semantics here are a bit broken. Linux will always use current
    42  	// for all reads, regardless of where the signalfd originated. We can't
    43  	// do exactly that because we need to plumb the context through
    44  	// EventRegister in order to support proper blocking behavior. This
    45  	// will undoubtedly become very complicated quickly.
    46  	target *kernel.Task
    47  
    48  	// queue is the queue for listeners.
    49  	queue waiter.Queue
    50  
    51  	// mu protects entry.
    52  	mu sync.Mutex `state:"nosave"`
    53  
    54  	// entry is the entry in the task signal queue.
    55  	entry waiter.Entry
    56  }
    57  
    58  var _ vfs.FileDescriptionImpl = (*SignalFileDescription)(nil)
    59  
    60  // New creates a new signal fd.
    61  func New(vfsObj *vfs.VirtualFilesystem, target *kernel.Task, mask linux.SignalSet, flags uint32) (*vfs.FileDescription, error) {
    62  	vd := vfsObj.NewAnonVirtualDentry("[signalfd]")
    63  	defer vd.DecRef(target)
    64  	sfd := &SignalFileDescription{
    65  		target: target,
    66  	}
    67  	sfd.entry.Init(sfd, waiter.EventMask(mask))
    68  	sfd.target.SignalRegister(&sfd.entry)
    69  	if err := sfd.vfsfd.Init(sfd, flags, vd.Mount(), vd.Dentry(), &vfs.FileDescriptionOptions{
    70  		UseDentryMetadata: true,
    71  		DenyPRead:         true,
    72  		DenyPWrite:        true,
    73  	}); err != nil {
    74  		sfd.target.SignalUnregister(&sfd.entry)
    75  		return nil, err
    76  	}
    77  	return &sfd.vfsfd, nil
    78  }
    79  
    80  // Mask returns the signal mask.
    81  func (sfd *SignalFileDescription) Mask() linux.SignalSet {
    82  	sfd.mu.Lock()
    83  	defer sfd.mu.Unlock()
    84  	return linux.SignalSet(sfd.entry.Mask())
    85  }
    86  
    87  // SetMask sets the signal mask.
    88  func (sfd *SignalFileDescription) SetMask(mask linux.SignalSet) {
    89  	sfd.mu.Lock()
    90  	defer sfd.mu.Unlock()
    91  	sfd.target.SignalUnregister(&sfd.entry)
    92  	sfd.entry.Init(sfd, waiter.EventMask(mask))
    93  	sfd.target.SignalRegister(&sfd.entry)
    94  }
    95  
    96  // Read implements vfs.FileDescriptionImpl.Read.
    97  func (sfd *SignalFileDescription) Read(ctx context.Context, dst usermem.IOSequence, _ vfs.ReadOptions) (int64, error) {
    98  	// Attempt to dequeue relevant signals.
    99  	info, err := sfd.target.Sigtimedwait(sfd.Mask(), 0)
   100  	if err != nil {
   101  		// There must be no signal available.
   102  		return 0, linuxerr.ErrWouldBlock
   103  	}
   104  
   105  	// Copy out the signal info using the specified format.
   106  	infoNative := linux.SignalfdSiginfo{
   107  		Signo:   uint32(info.Signo),
   108  		Errno:   info.Errno,
   109  		Code:    info.Code,
   110  		PID:     uint32(info.PID()),
   111  		UID:     uint32(info.UID()),
   112  		Status:  info.Status(),
   113  		Overrun: uint32(info.Overrun()),
   114  		Addr:    info.Addr(),
   115  	}
   116  	n, err := infoNative.WriteTo(dst.Writer(ctx))
   117  	if err == usermem.ErrEndOfIOSequence {
   118  		// Partial copy-out ok.
   119  		err = nil
   120  	}
   121  	return n, err
   122  }
   123  
   124  // Readiness implements waiter.Waitable.Readiness.
   125  func (sfd *SignalFileDescription) Readiness(mask waiter.EventMask) waiter.EventMask {
   126  	sfd.mu.Lock()
   127  	defer sfd.mu.Unlock()
   128  	if mask&waiter.ReadableEvents != 0 && sfd.target.PendingSignals()&linux.SignalSet(sfd.entry.Mask()) != 0 {
   129  		return waiter.ReadableEvents // Pending signals.
   130  	}
   131  	return 0
   132  }
   133  
   134  // EventRegister implements waiter.Waitable.EventRegister.
   135  func (sfd *SignalFileDescription) EventRegister(e *waiter.Entry) error {
   136  	sfd.queue.EventRegister(e)
   137  	return nil
   138  }
   139  
   140  // EventUnregister implements waiter.Waitable.EventUnregister.
   141  func (sfd *SignalFileDescription) EventUnregister(e *waiter.Entry) {
   142  	sfd.queue.EventUnregister(e)
   143  }
   144  
   145  // NotifyEvent implements waiter.EventListener.NotifyEvent.
   146  func (sfd *SignalFileDescription) NotifyEvent(mask waiter.EventMask) {
   147  	sfd.queue.Notify(waiter.EventIn) // Always notify data available.
   148  }
   149  
   150  // Epollable implements FileDescriptionImpl.Epollable.
   151  func (sfd *SignalFileDescription) Epollable() bool {
   152  	return true
   153  }
   154  
   155  // Release implements vfs.FileDescriptionImpl.Release.
   156  func (sfd *SignalFileDescription) Release(context.Context) {
   157  	sfd.target.SignalUnregister(&sfd.entry)
   158  }
   159  
   160  // RegisterFileAsyncHandler implements vfs.FileDescriptionImpl.RegisterFileAsyncHandler.
   161  func (sfd *SignalFileDescription) RegisterFileAsyncHandler(fd *vfs.FileDescription) error {
   162  	return sfd.NoAsyncEventFD.RegisterFileAsyncHandler(fd)
   163  }
   164  
   165  // UnregisterFileAsyncHandler implements vfs.FileDescriptionImpl.UnregisterFileAsyncHandler.
   166  func (sfd *SignalFileDescription) UnregisterFileAsyncHandler(fd *vfs.FileDescription) {
   167  	sfd.NoAsyncEventFD.UnregisterFileAsyncHandler(fd)
   168  }