github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/syscalls/linux/sys_signal.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  	"math"
    19  	"time"
    20  
    21  	"github.com/ttpreport/gvisor-ligolo/pkg/abi/linux"
    22  	"github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr"
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/hostarch"
    24  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/arch"
    25  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/fsimpl/signalfd"
    26  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel"
    27  )
    28  
    29  // "For a process to have permission to send a signal it must
    30  //   - either be privileged (CAP_KILL), or
    31  //   - the real or effective user ID of the sending process must be equal to the
    32  //
    33  // real or saved set-user-ID of the target process.
    34  //
    35  // In the case of SIGCONT it suffices when the sending and receiving processes
    36  // belong to the same session." - kill(2)
    37  //
    38  // Equivalent to kernel/signal.c:check_kill_permission.
    39  func mayKill(t *kernel.Task, target *kernel.Task, sig linux.Signal) bool {
    40  	// kernel/signal.c:check_kill_permission also allows a signal if the
    41  	// sending and receiving tasks share a thread group, which is not
    42  	// mentioned in kill(2) since kill does not allow task-level
    43  	// granularity in signal sending.
    44  	if t.ThreadGroup() == target.ThreadGroup() {
    45  		return true
    46  	}
    47  
    48  	if t.HasCapabilityIn(linux.CAP_KILL, target.UserNamespace()) {
    49  		return true
    50  	}
    51  
    52  	creds := t.Credentials()
    53  	tcreds := target.Credentials()
    54  	if creds.EffectiveKUID == tcreds.SavedKUID ||
    55  		creds.EffectiveKUID == tcreds.RealKUID ||
    56  		creds.RealKUID == tcreds.SavedKUID ||
    57  		creds.RealKUID == tcreds.RealKUID {
    58  		return true
    59  	}
    60  
    61  	if sig == linux.SIGCONT && target.ThreadGroup().Session() == t.ThreadGroup().Session() {
    62  		return true
    63  	}
    64  	return false
    65  }
    66  
    67  // Kill implements linux syscall kill(2).
    68  func Kill(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    69  	pid := kernel.ThreadID(args[0].Int())
    70  	sig := linux.Signal(args[1].Int())
    71  
    72  	switch {
    73  	case pid > 0:
    74  		// "If pid is positive, then signal sig is sent to the process with the
    75  		// ID specified by pid." - kill(2)
    76  		// This loops to handle races with execve where target dies between
    77  		// TaskWithID and SendGroupSignal. Compare Linux's
    78  		// kernel/signal.c:kill_pid_info().
    79  		for {
    80  			target := t.PIDNamespace().TaskWithID(pid)
    81  			if target == nil {
    82  				return 0, nil, linuxerr.ESRCH
    83  			}
    84  			if !mayKill(t, target, sig) {
    85  				return 0, nil, linuxerr.EPERM
    86  			}
    87  			info := &linux.SignalInfo{
    88  				Signo: int32(sig),
    89  				Code:  linux.SI_USER,
    90  			}
    91  			info.SetPID(int32(target.PIDNamespace().IDOfTask(t)))
    92  			info.SetUID(int32(t.Credentials().RealKUID.In(target.UserNamespace()).OrOverflow()))
    93  			if err := target.SendGroupSignal(info); !linuxerr.Equals(linuxerr.ESRCH, err) {
    94  				return 0, nil, err
    95  			}
    96  		}
    97  	case pid == -1:
    98  		// "If pid equals -1, then sig is sent to every process for which the
    99  		// calling process has permission to send signals, except for process 1
   100  		// (init), but see below. ... POSIX.1-2001 requires that kill(-1,sig)
   101  		// send sig to all processes that the calling process may send signals
   102  		// to, except possibly for some implementation-defined system
   103  		// processes. Linux allows a process to signal itself, but on Linux the
   104  		// call kill(-1,sig) does not signal the calling process."
   105  		var (
   106  			lastErr   error
   107  			delivered int
   108  		)
   109  		for _, tg := range t.PIDNamespace().ThreadGroups() {
   110  			if tg == t.ThreadGroup() {
   111  				continue
   112  			}
   113  			// Don't send the signal to the init process in t's PID namespace.
   114  			if tg.IsInitIn(t.PIDNamespace()) {
   115  				continue
   116  			}
   117  
   118  			// If pid == -1, the returned error is the last non-EPERM error
   119  			// from any call to group_send_sig_info.
   120  			if !mayKill(t, tg.Leader(), sig) {
   121  				continue
   122  			}
   123  			// Here and below, whether or not kill returns an error may
   124  			// depend on the iteration order. We at least implement the
   125  			// semantics documented by the man page: "On success (at least
   126  			// one signal was sent), zero is returned."
   127  			info := &linux.SignalInfo{
   128  				Signo: int32(sig),
   129  				Code:  linux.SI_USER,
   130  			}
   131  			info.SetPID(int32(tg.PIDNamespace().IDOfTask(t)))
   132  			info.SetUID(int32(t.Credentials().RealKUID.In(tg.Leader().UserNamespace()).OrOverflow()))
   133  			err := tg.SendSignal(info)
   134  			if linuxerr.Equals(linuxerr.ESRCH, err) {
   135  				// ESRCH is ignored because it means the task
   136  				// exited while we were iterating.  This is a
   137  				// race which would not normally exist on
   138  				// Linux, so we suppress it.
   139  				continue
   140  			}
   141  			delivered++
   142  			if err != nil {
   143  				lastErr = err
   144  			}
   145  		}
   146  		if delivered > 0 {
   147  			return 0, nil, lastErr
   148  		}
   149  		return 0, nil, linuxerr.ESRCH
   150  	default:
   151  		// "If pid equals 0, then sig is sent to every process in the process
   152  		// group of the calling process."
   153  		//
   154  		// "If pid is less than -1, then sig is sent to every process
   155  		// in the process group whose ID is -pid."
   156  		pgid := kernel.ProcessGroupID(-pid)
   157  		if pgid == 0 {
   158  			pgid = t.PIDNamespace().IDOfProcessGroup(t.ThreadGroup().ProcessGroup())
   159  		}
   160  
   161  		// If pid != -1 (i.e. signalling a process group), the returned error
   162  		// is the last error from any call to group_send_sig_info.
   163  		lastErr := error(linuxerr.ESRCH)
   164  		for _, tg := range t.PIDNamespace().ThreadGroups() {
   165  			if t.PIDNamespace().IDOfProcessGroup(tg.ProcessGroup()) == pgid {
   166  				if !mayKill(t, tg.Leader(), sig) {
   167  					lastErr = linuxerr.EPERM
   168  					continue
   169  				}
   170  
   171  				info := &linux.SignalInfo{
   172  					Signo: int32(sig),
   173  					Code:  linux.SI_USER,
   174  				}
   175  				info.SetPID(int32(tg.PIDNamespace().IDOfTask(t)))
   176  				info.SetUID(int32(t.Credentials().RealKUID.In(tg.Leader().UserNamespace()).OrOverflow()))
   177  				// See note above regarding ESRCH race above.
   178  				if err := tg.SendSignal(info); !linuxerr.Equals(linuxerr.ESRCH, err) {
   179  					lastErr = err
   180  				}
   181  			}
   182  		}
   183  
   184  		return 0, nil, lastErr
   185  	}
   186  }
   187  
   188  func tkillSigInfo(sender, receiver *kernel.Task, sig linux.Signal) *linux.SignalInfo {
   189  	info := &linux.SignalInfo{
   190  		Signo: int32(sig),
   191  		Code:  linux.SI_TKILL,
   192  	}
   193  	info.SetPID(int32(receiver.PIDNamespace().IDOfThreadGroup(sender.ThreadGroup())))
   194  	info.SetUID(int32(sender.Credentials().RealKUID.In(receiver.UserNamespace()).OrOverflow()))
   195  	return info
   196  }
   197  
   198  // Tkill implements linux syscall tkill(2).
   199  func Tkill(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   200  	tid := kernel.ThreadID(args[0].Int())
   201  	sig := linux.Signal(args[1].Int())
   202  
   203  	// N.B. Inconsistent with man page, linux actually rejects calls with
   204  	// tid <=0 by EINVAL. This isn't the same for all signal calls.
   205  	if tid <= 0 {
   206  		return 0, nil, linuxerr.EINVAL
   207  	}
   208  
   209  	target := t.PIDNamespace().TaskWithID(tid)
   210  	if target == nil {
   211  		return 0, nil, linuxerr.ESRCH
   212  	}
   213  
   214  	if !mayKill(t, target, sig) {
   215  		return 0, nil, linuxerr.EPERM
   216  	}
   217  	return 0, nil, target.SendSignal(tkillSigInfo(t, target, sig))
   218  }
   219  
   220  // Tgkill implements linux syscall tgkill(2).
   221  func Tgkill(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   222  	tgid := kernel.ThreadID(args[0].Int())
   223  	tid := kernel.ThreadID(args[1].Int())
   224  	sig := linux.Signal(args[2].Int())
   225  
   226  	// N.B. Inconsistent with man page, linux actually rejects calls with
   227  	// tgid/tid <=0 by EINVAL. This isn't the same for all signal calls.
   228  	if tgid <= 0 || tid <= 0 {
   229  		return 0, nil, linuxerr.EINVAL
   230  	}
   231  
   232  	targetTG := t.PIDNamespace().ThreadGroupWithID(tgid)
   233  	target := t.PIDNamespace().TaskWithID(tid)
   234  	if targetTG == nil || target == nil || target.ThreadGroup() != targetTG {
   235  		return 0, nil, linuxerr.ESRCH
   236  	}
   237  
   238  	if !mayKill(t, target, sig) {
   239  		return 0, nil, linuxerr.EPERM
   240  	}
   241  	return 0, nil, target.SendSignal(tkillSigInfo(t, target, sig))
   242  }
   243  
   244  // RtSigaction implements linux syscall rt_sigaction(2).
   245  func RtSigaction(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   246  	sig := linux.Signal(args[0].Int())
   247  	newactarg := args[1].Pointer()
   248  	oldactarg := args[2].Pointer()
   249  	sigsetsize := args[3].SizeT()
   250  
   251  	if sigsetsize != linux.SignalSetSize {
   252  		return 0, nil, linuxerr.EINVAL
   253  	}
   254  
   255  	var newactptr *linux.SigAction
   256  	if newactarg != 0 {
   257  		var newact linux.SigAction
   258  		if _, err := newact.CopyIn(t, newactarg); err != nil {
   259  			return 0, nil, err
   260  		}
   261  		newactptr = &newact
   262  	}
   263  	oldact, err := t.ThreadGroup().SetSigAction(sig, newactptr)
   264  	if err != nil {
   265  		return 0, nil, err
   266  	}
   267  	if oldactarg != 0 {
   268  		if _, err := oldact.CopyOut(t, oldactarg); err != nil {
   269  			return 0, nil, err
   270  		}
   271  	}
   272  	return 0, nil, nil
   273  }
   274  
   275  // Sigreturn implements linux syscall sigreturn(2).
   276  func Sigreturn(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   277  	ctrl, err := t.SignalReturn(false)
   278  	return 0, ctrl, err
   279  }
   280  
   281  // RtSigreturn implements linux syscall rt_sigreturn(2).
   282  func RtSigreturn(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   283  	ctrl, err := t.SignalReturn(true)
   284  	return 0, ctrl, err
   285  }
   286  
   287  // RtSigprocmask implements linux syscall rt_sigprocmask(2).
   288  func RtSigprocmask(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   289  	how := args[0].Int()
   290  	setaddr := args[1].Pointer()
   291  	oldaddr := args[2].Pointer()
   292  	sigsetsize := args[3].SizeT()
   293  
   294  	if sigsetsize != linux.SignalSetSize {
   295  		return 0, nil, linuxerr.EINVAL
   296  	}
   297  	oldmask := t.SignalMask()
   298  	if setaddr != 0 {
   299  		mask, err := copyInSigSet(t, setaddr, sigsetsize)
   300  		if err != nil {
   301  			return 0, nil, err
   302  		}
   303  
   304  		switch how {
   305  		case linux.SIG_BLOCK:
   306  			t.SetSignalMask(oldmask | mask)
   307  		case linux.SIG_UNBLOCK:
   308  			t.SetSignalMask(oldmask &^ mask)
   309  		case linux.SIG_SETMASK:
   310  			t.SetSignalMask(mask)
   311  		default:
   312  			return 0, nil, linuxerr.EINVAL
   313  		}
   314  	}
   315  	if oldaddr != 0 {
   316  		return 0, nil, copyOutSigSet(t, oldaddr, oldmask)
   317  	}
   318  
   319  	return 0, nil, nil
   320  }
   321  
   322  // Sigaltstack implements linux syscall sigaltstack(2).
   323  func Sigaltstack(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   324  	setaddr := args[0].Pointer()
   325  	oldaddr := args[1].Pointer()
   326  
   327  	ctrl, err := t.SigaltStack(setaddr, oldaddr)
   328  	return 0, ctrl, err
   329  }
   330  
   331  // Pause implements linux syscall pause(2).
   332  func Pause(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   333  	return 0, nil, linuxerr.ConvertIntr(t.Block(nil), linuxerr.ERESTARTNOHAND)
   334  }
   335  
   336  // RtSigpending implements linux syscall rt_sigpending(2).
   337  func RtSigpending(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   338  	addr := args[0].Pointer()
   339  	pending := t.PendingSignals()
   340  	_, err := pending.CopyOut(t, addr)
   341  	return 0, nil, err
   342  }
   343  
   344  // RtSigtimedwait implements linux syscall rt_sigtimedwait(2).
   345  func RtSigtimedwait(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   346  	sigset := args[0].Pointer()
   347  	siginfo := args[1].Pointer()
   348  	timespec := args[2].Pointer()
   349  	sigsetsize := args[3].SizeT()
   350  
   351  	mask, err := copyInSigSet(t, sigset, sigsetsize)
   352  	if err != nil {
   353  		return 0, nil, err
   354  	}
   355  
   356  	var timeout time.Duration
   357  	if timespec != 0 {
   358  		d, err := copyTimespecIn(t, timespec)
   359  		if err != nil {
   360  			return 0, nil, err
   361  		}
   362  		if !d.Valid() {
   363  			return 0, nil, linuxerr.EINVAL
   364  		}
   365  		timeout = time.Duration(d.ToNsecCapped())
   366  	} else {
   367  		timeout = time.Duration(math.MaxInt64)
   368  	}
   369  
   370  	si, err := t.Sigtimedwait(mask, timeout)
   371  	if err != nil {
   372  		return 0, nil, err
   373  	}
   374  
   375  	if siginfo != 0 {
   376  		si.FixSignalCodeForUser()
   377  		if _, err := si.CopyOut(t, siginfo); err != nil {
   378  			return 0, nil, err
   379  		}
   380  	}
   381  	return uintptr(si.Signo), nil, nil
   382  }
   383  
   384  // RtSigqueueinfo implements linux syscall rt_sigqueueinfo(2).
   385  func RtSigqueueinfo(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   386  	pid := kernel.ThreadID(args[0].Int())
   387  	sig := linux.Signal(args[1].Int())
   388  	infoAddr := args[2].Pointer()
   389  
   390  	// Copy in the info.
   391  	//
   392  	// We must ensure that the Signo is set (Linux overrides this in the
   393  	// same way), and that the code is in the allowed set. This same logic
   394  	// appears below in RtSigtgqueueinfo and should be kept in sync.
   395  	var info linux.SignalInfo
   396  	if _, err := info.CopyIn(t, infoAddr); err != nil {
   397  		return 0, nil, err
   398  	}
   399  	info.Signo = int32(sig)
   400  
   401  	// This must loop to handle the race with execve described in Kill.
   402  	for {
   403  		// Deliver to the given task's thread group.
   404  		target := t.PIDNamespace().TaskWithID(pid)
   405  		if target == nil {
   406  			return 0, nil, linuxerr.ESRCH
   407  		}
   408  
   409  		// If the sender is not the receiver, it can't use si_codes used by the
   410  		// kernel or SI_TKILL.
   411  		if (info.Code >= 0 || info.Code == linux.SI_TKILL) && target != t {
   412  			return 0, nil, linuxerr.EPERM
   413  		}
   414  
   415  		if !mayKill(t, target, sig) {
   416  			return 0, nil, linuxerr.EPERM
   417  		}
   418  
   419  		if err := target.SendGroupSignal(&info); !linuxerr.Equals(linuxerr.ESRCH, err) {
   420  			return 0, nil, err
   421  		}
   422  	}
   423  }
   424  
   425  // RtTgsigqueueinfo implements linux syscall rt_tgsigqueueinfo(2).
   426  func RtTgsigqueueinfo(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   427  	tgid := kernel.ThreadID(args[0].Int())
   428  	tid := kernel.ThreadID(args[1].Int())
   429  	sig := linux.Signal(args[2].Int())
   430  	infoAddr := args[3].Pointer()
   431  
   432  	// N.B. Inconsistent with man page, linux actually rejects calls with
   433  	// tgid/tid <=0 by EINVAL. This isn't the same for all signal calls.
   434  	if tgid <= 0 || tid <= 0 {
   435  		return 0, nil, linuxerr.EINVAL
   436  	}
   437  
   438  	// Copy in the info. See RtSigqueueinfo above.
   439  	var info linux.SignalInfo
   440  	if _, err := info.CopyIn(t, infoAddr); err != nil {
   441  		return 0, nil, err
   442  	}
   443  	info.Signo = int32(sig)
   444  
   445  	// Deliver to the given task.
   446  	targetTG := t.PIDNamespace().ThreadGroupWithID(tgid)
   447  	target := t.PIDNamespace().TaskWithID(tid)
   448  	if targetTG == nil || target == nil || target.ThreadGroup() != targetTG {
   449  		return 0, nil, linuxerr.ESRCH
   450  	}
   451  
   452  	// If the sender is not the receiver, it can't use si_codes used by the
   453  	// kernel or SI_TKILL.
   454  	if (info.Code >= 0 || info.Code == linux.SI_TKILL) && target != t {
   455  		return 0, nil, linuxerr.EPERM
   456  	}
   457  
   458  	if !mayKill(t, target, sig) {
   459  		return 0, nil, linuxerr.EPERM
   460  	}
   461  	return 0, nil, target.SendSignal(&info)
   462  }
   463  
   464  // RtSigsuspend implements linux syscall rt_sigsuspend(2).
   465  func RtSigsuspend(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   466  	sigset := args[0].Pointer()
   467  
   468  	// Copy in the signal mask.
   469  	var mask linux.SignalSet
   470  	if _, err := mask.CopyIn(t, sigset); err != nil {
   471  		return 0, nil, err
   472  	}
   473  	mask &^= kernel.UnblockableSignals
   474  
   475  	// Swap the mask.
   476  	oldmask := t.SignalMask()
   477  	t.SetSignalMask(mask)
   478  	t.SetSavedSignalMask(oldmask)
   479  
   480  	// Perform the wait.
   481  	return 0, nil, linuxerr.ConvertIntr(t.Block(nil), linuxerr.ERESTARTNOHAND)
   482  }
   483  
   484  // RestartSyscall implements the linux syscall restart_syscall(2).
   485  func RestartSyscall(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   486  	if r := t.SyscallRestartBlock(); r != nil {
   487  		n, err := r.Restart(t)
   488  		return n, nil, err
   489  	}
   490  	// The restart block should never be nil here, but it's possible
   491  	// ERESTART_RESTARTBLOCK was set by ptrace without the current syscall
   492  	// setting up a restart block. If ptrace didn't manipulate the return value,
   493  	// finding a nil restart block is a bug. Linux ensures that the restart
   494  	// function is never null by (re)initializing it with one that translates
   495  	// the restart into EINTR. We'll emulate that behaviour.
   496  	t.Debugf("Restart block missing in restart_syscall(2). Did ptrace inject a return value of ERESTART_RESTARTBLOCK?")
   497  	return 0, nil, linuxerr.EINTR
   498  }
   499  
   500  // sharedSignalfd is shared between the two calls.
   501  func sharedSignalfd(t *kernel.Task, fd int32, sigset hostarch.Addr, sigsetsize uint, flags int32) (uintptr, *kernel.SyscallControl, error) {
   502  	// Copy in the signal mask.
   503  	mask, err := copyInSigSet(t, sigset, sigsetsize)
   504  	if err != nil {
   505  		return 0, nil, err
   506  	}
   507  
   508  	// Always check for valid flags, even if not creating.
   509  	if flags&^(linux.SFD_NONBLOCK|linux.SFD_CLOEXEC) != 0 {
   510  		return 0, nil, linuxerr.EINVAL
   511  	}
   512  
   513  	// Is this a change to an existing signalfd?
   514  	//
   515  	// The spec indicates that this should adjust the mask.
   516  	if fd != -1 {
   517  		file := t.GetFile(fd)
   518  		if file == nil {
   519  			return 0, nil, linuxerr.EBADF
   520  		}
   521  		defer file.DecRef(t)
   522  
   523  		// Is this a signalfd?
   524  		if sfd, ok := file.Impl().(*signalfd.SignalFileDescription); ok {
   525  			sfd.SetMask(mask)
   526  			return 0, nil, nil
   527  		}
   528  
   529  		// Not a signalfd.
   530  		return 0, nil, linuxerr.EINVAL
   531  	}
   532  
   533  	fileFlags := uint32(linux.O_RDWR)
   534  	if flags&linux.SFD_NONBLOCK != 0 {
   535  		fileFlags |= linux.O_NONBLOCK
   536  	}
   537  
   538  	// Create a new file.
   539  	vfsObj := t.Kernel().VFS()
   540  	file, err := signalfd.New(vfsObj, t, mask, fileFlags)
   541  	if err != nil {
   542  		return 0, nil, err
   543  	}
   544  	defer file.DecRef(t)
   545  
   546  	// Create a new descriptor.
   547  	fd, err = t.NewFDFrom(0, file, kernel.FDFlags{
   548  		CloseOnExec: flags&linux.SFD_CLOEXEC != 0,
   549  	})
   550  	if err != nil {
   551  		return 0, nil, err
   552  	}
   553  
   554  	// Done.
   555  	return uintptr(fd), nil, nil
   556  }
   557  
   558  // Signalfd implements the linux syscall signalfd(2).
   559  func Signalfd(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   560  	fd := args[0].Int()
   561  	sigset := args[1].Pointer()
   562  	sigsetsize := args[2].SizeT()
   563  	return sharedSignalfd(t, fd, sigset, sigsetsize, 0)
   564  }
   565  
   566  // Signalfd4 implements the linux syscall signalfd4(2).
   567  func Signalfd4(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   568  	fd := args[0].Int()
   569  	sigset := args[1].Pointer()
   570  	sigsetsize := args[2].SizeT()
   571  	flags := args[3].Int()
   572  	return sharedSignalfd(t, fd, sigset, sigsetsize, flags)
   573  }