| 
									
										
										
										
											2022-06-09 16:11:32 +08:00
										 |  |  | //go:build linux && seccomp
 | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package chroot | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2022-07-06 17:14:06 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2021-10-27 05:16:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 23:45:56 +08:00
										 |  |  | 	specs "github.com/opencontainers/runtime-spec/specs-go" | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 	libseccomp "github.com/seccomp/libseccomp-golang" | 
					
						
							|  |  |  | 	"github.com/sirupsen/logrus" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // setSeccomp sets the seccomp filter for ourselves and any processes that we'll start.
 | 
					
						
							|  |  |  | func setSeccomp(spec *specs.Spec) error { | 
					
						
							|  |  |  | 	logrus.Debugf("setting seccomp configuration") | 
					
						
							|  |  |  | 	if spec.Linux.Seccomp == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-24 05:44:29 +08:00
										 |  |  | 	mapAction := func(specAction specs.LinuxSeccompAction, errnoRet *uint) libseccomp.ScmpAction { | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 		switch specAction { | 
					
						
							|  |  |  | 		case specs.ActKill: | 
					
						
							| 
									
										
										
										
											2022-06-09 16:11:32 +08:00
										 |  |  | 			return libseccomp.ActKillThread | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 		case specs.ActTrap: | 
					
						
							|  |  |  | 			return libseccomp.ActTrap | 
					
						
							|  |  |  | 		case specs.ActErrno: | 
					
						
							| 
									
										
										
										
											2020-09-24 05:44:29 +08:00
										 |  |  | 			action := libseccomp.ActErrno | 
					
						
							|  |  |  | 			if errnoRet != nil { | 
					
						
							|  |  |  | 				action = action.SetReturnCode(int16(*errnoRet)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return action | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 		case specs.ActTrace: | 
					
						
							|  |  |  | 			return libseccomp.ActTrace | 
					
						
							|  |  |  | 		case specs.ActAllow: | 
					
						
							|  |  |  | 			return libseccomp.ActAllow | 
					
						
							| 
									
										
										
										
											2020-09-24 05:44:29 +08:00
										 |  |  | 		case specs.ActLog: | 
					
						
							|  |  |  | 			return libseccomp.ActLog | 
					
						
							|  |  |  | 		case specs.ActKillProcess: | 
					
						
							|  |  |  | 			return libseccomp.ActKillProcess | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			logrus.Errorf("unmappable action %v", specAction) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return libseccomp.ActInvalid | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mapArch := func(specArch specs.Arch) libseccomp.ScmpArch { | 
					
						
							|  |  |  | 		switch specArch { | 
					
						
							|  |  |  | 		case specs.ArchX86: | 
					
						
							|  |  |  | 			return libseccomp.ArchX86 | 
					
						
							|  |  |  | 		case specs.ArchX86_64: | 
					
						
							|  |  |  | 			return libseccomp.ArchAMD64 | 
					
						
							|  |  |  | 		case specs.ArchX32: | 
					
						
							|  |  |  | 			return libseccomp.ArchX32 | 
					
						
							|  |  |  | 		case specs.ArchARM: | 
					
						
							|  |  |  | 			return libseccomp.ArchARM | 
					
						
							|  |  |  | 		case specs.ArchAARCH64: | 
					
						
							|  |  |  | 			return libseccomp.ArchARM64 | 
					
						
							|  |  |  | 		case specs.ArchMIPS: | 
					
						
							|  |  |  | 			return libseccomp.ArchMIPS | 
					
						
							|  |  |  | 		case specs.ArchMIPS64: | 
					
						
							|  |  |  | 			return libseccomp.ArchMIPS64 | 
					
						
							|  |  |  | 		case specs.ArchMIPS64N32: | 
					
						
							|  |  |  | 			return libseccomp.ArchMIPS64N32 | 
					
						
							|  |  |  | 		case specs.ArchMIPSEL: | 
					
						
							|  |  |  | 			return libseccomp.ArchMIPSEL | 
					
						
							|  |  |  | 		case specs.ArchMIPSEL64: | 
					
						
							|  |  |  | 			return libseccomp.ArchMIPSEL64 | 
					
						
							|  |  |  | 		case specs.ArchMIPSEL64N32: | 
					
						
							|  |  |  | 			return libseccomp.ArchMIPSEL64N32 | 
					
						
							|  |  |  | 		case specs.ArchPPC: | 
					
						
							|  |  |  | 			return libseccomp.ArchPPC | 
					
						
							|  |  |  | 		case specs.ArchPPC64: | 
					
						
							|  |  |  | 			return libseccomp.ArchPPC64 | 
					
						
							|  |  |  | 		case specs.ArchPPC64LE: | 
					
						
							|  |  |  | 			return libseccomp.ArchPPC64LE | 
					
						
							|  |  |  | 		case specs.ArchS390: | 
					
						
							|  |  |  | 			return libseccomp.ArchS390 | 
					
						
							|  |  |  | 		case specs.ArchS390X: | 
					
						
							|  |  |  | 			return libseccomp.ArchS390X | 
					
						
							|  |  |  | 		case specs.ArchPARISC: | 
					
						
							| 
									
										
										
										
											2023-08-14 21:51:12 +08:00
										 |  |  | 			return libseccomp.ArchPARISC | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 		case specs.ArchPARISC64: | 
					
						
							| 
									
										
										
										
											2023-08-14 21:51:12 +08:00
										 |  |  | 			return libseccomp.ArchPARISC64 | 
					
						
							|  |  |  | 		case specs.ArchRISCV64: | 
					
						
							|  |  |  | 			return libseccomp.ArchRISCV64 | 
					
						
							| 
									
										
										
										
											2020-09-24 05:44:29 +08:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 			logrus.Errorf("unmappable arch %v", specArch) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return libseccomp.ArchInvalid | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mapOp := func(op specs.LinuxSeccompOperator) libseccomp.ScmpCompareOp { | 
					
						
							|  |  |  | 		switch op { | 
					
						
							|  |  |  | 		case specs.OpNotEqual: | 
					
						
							|  |  |  | 			return libseccomp.CompareNotEqual | 
					
						
							|  |  |  | 		case specs.OpLessThan: | 
					
						
							|  |  |  | 			return libseccomp.CompareLess | 
					
						
							|  |  |  | 		case specs.OpLessEqual: | 
					
						
							|  |  |  | 			return libseccomp.CompareLessOrEqual | 
					
						
							|  |  |  | 		case specs.OpEqualTo: | 
					
						
							|  |  |  | 			return libseccomp.CompareEqual | 
					
						
							|  |  |  | 		case specs.OpGreaterEqual: | 
					
						
							|  |  |  | 			return libseccomp.CompareGreaterEqual | 
					
						
							|  |  |  | 		case specs.OpGreaterThan: | 
					
						
							|  |  |  | 			return libseccomp.CompareGreater | 
					
						
							|  |  |  | 		case specs.OpMaskedEqual: | 
					
						
							|  |  |  | 			return libseccomp.CompareMaskedEqual | 
					
						
							| 
									
										
										
										
											2020-09-24 05:44:29 +08:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 			logrus.Errorf("unmappable op %v", op) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return libseccomp.CompareInvalid | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-07 22:41:17 +08:00
										 |  |  | 	filter, err := libseccomp.NewFilter(mapAction(spec.Linux.Seccomp.DefaultAction, spec.Linux.Seccomp.DefaultErrnoRet)) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 		return fmt.Errorf("creating seccomp filter with default action %q: %w", spec.Linux.Seccomp.DefaultAction, err) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, arch := range spec.Linux.Seccomp.Architectures { | 
					
						
							|  |  |  | 		if err = filter.AddArch(mapArch(arch)); err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 			return fmt.Errorf("adding architecture %q(%q) to seccomp filter: %w", arch, mapArch(arch), err) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, rule := range spec.Linux.Seccomp.Syscalls { | 
					
						
							|  |  |  | 		scnames := make(map[libseccomp.ScmpSyscall]string) | 
					
						
							|  |  |  | 		for _, name := range rule.Names { | 
					
						
							|  |  |  | 			scnum, err := libseccomp.GetSyscallFromName(name) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-30 23:36:52 +08:00
										 |  |  | 				logrus.Debugf("error mapping syscall %q to a syscall, ignoring %q rule for %q", name, rule.Action, name) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			scnames[scnum] = name | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for scnum := range scnames { | 
					
						
							|  |  |  | 			if len(rule.Args) == 0 { | 
					
						
							| 
									
										
										
										
											2020-09-24 05:44:29 +08:00
										 |  |  | 				if err = filter.AddRule(scnum, mapAction(rule.Action, rule.ErrnoRet)); err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 					return fmt.Errorf("adding a rule (%q:%q) to seccomp filter: %w", scnames[scnum], rule.Action, err) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var conditions []libseccomp.ScmpCondition | 
					
						
							| 
									
										
										
										
											2020-01-17 23:45:56 +08:00
										 |  |  | 			opsAreAllEquality := true | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 			for _, arg := range rule.Args { | 
					
						
							|  |  |  | 				condition, err := libseccomp.MakeCondition(arg.Index, mapOp(arg.Op), arg.Value, arg.ValueTwo) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 					return fmt.Errorf("building a seccomp condition %d:%v:%d:%d: %w", arg.Index, arg.Op, arg.Value, arg.ValueTwo, err) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-01-17 23:45:56 +08:00
										 |  |  | 				if arg.Op != specs.OpEqualTo { | 
					
						
							|  |  |  | 					opsAreAllEquality = false | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 				conditions = append(conditions, condition) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-09-24 05:44:29 +08:00
										 |  |  | 			if err = filter.AddRuleConditional(scnum, mapAction(rule.Action, rule.ErrnoRet), conditions); err != nil { | 
					
						
							| 
									
										
										
										
											2020-01-17 23:45:56 +08:00
										 |  |  | 				// Okay, if the rules specify multiple equality
 | 
					
						
							|  |  |  | 				// checks, assume someone thought that they
 | 
					
						
							|  |  |  | 				// were OR'd, when in fact they're ordinarily
 | 
					
						
							|  |  |  | 				// supposed to be AND'd.  Break them up into
 | 
					
						
							|  |  |  | 				// different rules to get that OR effect.
 | 
					
						
							|  |  |  | 				if len(rule.Args) > 1 && opsAreAllEquality && err.Error() == "two checks on same syscall argument" { | 
					
						
							|  |  |  | 					for i := range conditions { | 
					
						
							| 
									
										
										
										
											2020-09-24 05:44:29 +08:00
										 |  |  | 						if err = filter.AddRuleConditional(scnum, mapAction(rule.Action, rule.ErrnoRet), conditions[i:i+1]); err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 							return fmt.Errorf("adding a conditional rule (%q:%q[%d]) to seccomp filter: %w", scnames[scnum], rule.Action, i, err) | 
					
						
							| 
									
										
										
										
											2020-01-17 23:45:56 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 					return fmt.Errorf("adding a conditional rule (%q:%q) to seccomp filter: %w", scnames[scnum], rule.Action, err) | 
					
						
							| 
									
										
										
										
											2020-01-17 23:45:56 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err = filter.SetNoNewPrivsBit(spec.Process.NoNewPrivileges); err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 		return fmt.Errorf("setting no-new-privileges bit to %v: %w", spec.Process.NoNewPrivileges, err) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	err = filter.Load() | 
					
						
							|  |  |  | 	filter.Release() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 		return fmt.Errorf("activating seccomp filter: %w", err) | 
					
						
							| 
									
										
										
										
											2018-05-12 01:08:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |