singularity icon indicating copy to clipboard operation
singularity copied to clipboard

Use openat when possible

Open bauerm97 opened this issue 5 years ago • 5 comments

To prevent the possibility of any ToCToE attacks, we should use openat() when looking at a directory and later opening a file contained within that directory. This will require a bit of investigation into the code to find the locations where this pattern is applicable. As a starting point, here is every reference to *.Open() that exists in our codebase (excluding vendor/):

internal/app/singularity/oci_create_linux.go:	fb, err := os.Open(configJSON)
internal/app/singularity/oci_update_linux.go:		f, err := os.Open(args.FromFile)
internal/app/singularity/plugin_compile_linux.go:	fp, err := os.Open(objInput.Fname)
internal/app/singularity/plugin_compile_linux.go:	fp, err := os.Open(manifestInput.Fname)
internal/pkg/util/fs/files/passwd.go:	passwdFile, err := os.Open(path)
internal/pkg/util/fs/files/group.go:	groupFile, err := os.Open(path)
internal/pkg/instance/instance_linux.go:			r, err := os.Open(file)
internal/pkg/plugin/load.go:	pluginPointer, err := plugin.Open(path)
internal/pkg/plugin/binary.go:	return os.Open(m.configName())
internal/pkg/plugin/binary.go:	fh, err := os.Open(filename)
internal/pkg/test/privilege_darwin.go:	f, err := os.Open(fmt.Sprintf("/proc/%v/status", pid))
internal/pkg/test/privilege_linux.go:	f, err := os.Open(fmt.Sprintf("/proc/%v/status", pid))
internal/pkg/runtime/engines/config/parser.go:		c, err = os.Open(filepath)
internal/pkg/runtime/engines/singularity/container_linux.go:			f, err := syscall.Open("/proc/"+strconv.Itoa(pid)+"/ns/net", os.O_RDONLY, 0)
internal/pkg/runtime/engines/singularity/container_linux.go:			r, err := os.Open(resolvConf)
internal/pkg/runtime/engines/singularity/rpc/server/server_linux.go:		oldroot, err := os.Open("/")
internal/pkg/runtime/engines/singularity/prepare_linux.go:			f, err := os.Open(src)
internal/pkg/runtime/engines/singularity/prepare_linux.go:			f, err := os.Open(src)
internal/pkg/runtime/engines/singularity/prepare_linux.go:		f, err := os.Open(path)
internal/pkg/runtime/engines/oci/create_linux.go:		f, err := os.Open(fmt.Sprintf("/proc/%d/cgroup", pid))
internal/pkg/runtime/engines/oci/prepare_linux.go:			master, slave, err = pty.Open()
internal/pkg/build/assemblers/assembler_sif.go:	fp, err := os.Open(parinput.Fname)
internal/pkg/build/build.go:	defFile, err := os.Open(spec)
internal/pkg/build/build.go:	defFile, err := os.Open(spec)
internal/pkg/build/sources/conveyorPacker_arch_test.go:	defFile, err := os.Open(archDef)
internal/pkg/build/sources/conveyorPacker_arch_test.go:	defFile, err := os.Open(archDef)
internal/pkg/build/sources/conveyorPacker_oci.go:	f, err := os.Open(src)
internal/pkg/build/sources/conveyorPacker_busybox_test.go:	defFile, err := os.Open(busyBoxDef)
internal/pkg/build/sources/conveyorPacker_busybox_test.go:	defFile, err := os.Open(busyBoxDef)
internal/pkg/build/sources/conveyorPacker_yum_test.go:	defFile, err := os.Open(yumDef)
internal/pkg/build/sources/conveyorPacker_yum_test.go:	defFile, err := os.Open(yumDef)
internal/pkg/build/sources/conveyorPacker_zypper_test.go:	defFile, err := os.Open(zyppDef)
internal/pkg/build/sources/conveyorPacker_zypper_test.go:	defFile, err := os.Open(zyppDef)
internal/pkg/build/sources/conveyorPacker_scratch_test.go:	defFile, err := os.Open(scratchDef)
internal/pkg/build/sources/conveyorPacker_scratch_test.go:	defFile, err := os.Open(scratchDef)
internal/pkg/build/metadata.go:		jsonFile, err := os.Open(filepath.Join(b.Rootfs(), "/.singularity.d/labels.json"))
internal/pkg/cgroups/cgroups_linux_test.go:	file, err := os.Open(path)
internal/pkg/cgroups/cgroups_linux_test.go:	file, err := os.Open(fmt.Sprintf("/proc/%d/status", manager.Pid))
internal/pkg/cgroups/cgroups_linux_test.go:	file, err = os.Open(fmt.Sprintf("/proc/%d/status", manager.Pid))
internal/pkg/security/seccomp/seccomp_linux.go:	file, err := os.Open(profile)
internal/pkg/syecl/syecl_test.go:	s, err := os.Open(src)
internal/pkg/syecl/syecl.go:	fp, err := os.Open(cpath)
pkg/util/fs/proc/proc.go:	p, err := os.Open("/proc/filesystems")
pkg/util/fs/proc/proc.go:	p, err := os.Open(path)
pkg/util/fs/proc/proc.go:	p, err := os.Open("/proc/self/mountinfo")
pkg/util/fs/proc/proc.go:		r, err := os.Open(filepath.Join(path, "status"))
pkg/util/fs/proc/proc.go:	r, err := os.Open(path)
pkg/util/fs/lock/lock.go:	fd, err = syscall.Open(path, os.O_RDONLY, 0)
pkg/util/nvidia/paths.go:	file, err := os.Open(nvliblistPath)
pkg/util/nvidia/paths.go:	self, err := elf.Open("/proc/self/exe")
pkg/util/nvidia/paths.go:					elib, err := elf.Open(libPath)
pkg/util/loop/loop_linux.go:		if loopFd, err = syscall.Open(path, mode, 0600); err != nil {
pkg/util/loop/loop_linux.go:	loop, err := os.Open(path)
pkg/util/loop/loop_linux_test.go:	f, err := os.Open("/etc/passwd")
pkg/util/namespaces/setns_linux.go:	f, err := os.Open(path)
pkg/client/library/util.go:	file, err := os.Open(filePath)
pkg/client/library/pull_test.go:	inFile, err := os.Open(m.testFile)
pkg/client/library/push.go:	f, err := os.Open(filePath)
pkg/sypgp/sypgp.go:	f, err := os.Open(SecretPath())
pkg/sypgp/sypgp.go:	f, err := os.Open(PublicPath())
pkg/sypgp/sypgp.go:	f, err := os.Open(path)
pkg/build/legacy/parser/deffile.go:	defFile, err := os.Open(source)
pkg/build/legacy/parser/deffile_test.go:			r, err := os.Open(deffile)
pkg/build/legacy/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/legacy/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/types/parser/deffile.go:	defFile, err := os.Open(source)
pkg/build/types/parser/deffile_test.go:			r, err := os.Open(deffile)
pkg/build/types/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/types/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/types/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/types/definition_test.go:	f, err := os.Open(singularityJSON)

I imagine that we'll be able to ignore a decent chunk of those, such as the pieces which are pertinent to image building. However, for the rest I think we'll want to go through and look for times where we open a file having first performed some type of validation of its' directory existing (or similar). Then we'll be able to come up with a list of places we can use Openat() and go on from there.

bauerm97 avatar Apr 22 '19 21:04 bauerm97

Slimming down the list, ignoring anything that only pertains to image building:

internal/app/singularity/oci_create_linux.go:	fb, err := os.Open(configJSON)
internal/app/singularity/oci_update_linux.go:		f, err := os.Open(args.FromFile)
internal/app/singularity/plugin_compile_linux.go:	fp, err := os.Open(objInput.Fname)
internal/app/singularity/plugin_compile_linux.go:	fp, err := os.Open(manifestInput.Fname)
internal/pkg/util/fs/files/passwd.go:	passwdFile, err := os.Open(path)
internal/pkg/util/fs/files/group.go:	groupFile, err := os.Open(path)
internal/pkg/instance/instance_linux.go:			r, err := os.Open(file)
internal/pkg/plugin/load.go:	pluginPointer, err := plugin.Open(path)
internal/pkg/plugin/binary.go:	return os.Open(m.configName())
internal/pkg/plugin/binary.go:	fh, err := os.Open(filename)
internal/pkg/test/privilege_darwin.go:	f, err := os.Open(fmt.Sprintf("/proc/%v/status", pid))
internal/pkg/test/privilege_linux.go:	f, err := os.Open(fmt.Sprintf("/proc/%v/status", pid))
internal/pkg/runtime/engines/config/parser.go:		c, err = os.Open(filepath)
internal/pkg/runtime/engines/singularity/container_linux.go:			f, err := syscall.Open("/proc/"+strconv.Itoa(pid)+"/ns/net", os.O_RDONLY, 0)
internal/pkg/runtime/engines/singularity/container_linux.go:			r, err := os.Open(resolvConf)
internal/pkg/runtime/engines/singularity/rpc/server/server_linux.go:		oldroot, err := os.Open("/")
internal/pkg/runtime/engines/singularity/prepare_linux.go:			f, err := os.Open(src)
internal/pkg/runtime/engines/singularity/prepare_linux.go:			f, err := os.Open(src)
internal/pkg/runtime/engines/singularity/prepare_linux.go:		f, err := os.Open(path)
internal/pkg/runtime/engines/oci/create_linux.go:		f, err := os.Open(fmt.Sprintf("/proc/%d/cgroup", pid))
internal/pkg/runtime/engines/oci/prepare_linux.go:			master, slave, err = pty.Open()
internal/pkg/cgroups/cgroups_linux_test.go:	file, err := os.Open(path)
internal/pkg/cgroups/cgroups_linux_test.go:	file, err := os.Open(fmt.Sprintf("/proc/%d/status", manager.Pid))
internal/pkg/cgroups/cgroups_linux_test.go:	file, err = os.Open(fmt.Sprintf("/proc/%d/status", manager.Pid))
internal/pkg/security/seccomp/seccomp_linux.go:	file, err := os.Open(profile)
internal/pkg/syecl/syecl_test.go:	s, err := os.Open(src)
internal/pkg/syecl/syecl.go:	fp, err := os.Open(cpath)
pkg/util/fs/proc/proc.go:	p, err := os.Open("/proc/filesystems")
pkg/util/fs/proc/proc.go:	p, err := os.Open(path)
pkg/util/fs/proc/proc.go:	p, err := os.Open("/proc/self/mountinfo")
pkg/util/fs/proc/proc.go:		r, err := os.Open(filepath.Join(path, "status"))
pkg/util/fs/proc/proc.go:	r, err := os.Open(path)
pkg/util/fs/lock/lock.go:	fd, err = syscall.Open(path, os.O_RDONLY, 0)
pkg/util/nvidia/paths.go:	file, err := os.Open(nvliblistPath)
pkg/util/nvidia/paths.go:	self, err := elf.Open("/proc/self/exe")
pkg/util/nvidia/paths.go:					elib, err := elf.Open(libPath)
pkg/util/loop/loop_linux.go:		if loopFd, err = syscall.Open(path, mode, 0600); err != nil {
pkg/util/loop/loop_linux.go:	loop, err := os.Open(path)
pkg/util/loop/loop_linux_test.go:	f, err := os.Open("/etc/passwd")
pkg/util/namespaces/setns_linux.go:	f, err := os.Open(path)
pkg/client/library/util.go:	file, err := os.Open(filePath)
pkg/client/library/pull_test.go:	inFile, err := os.Open(m.testFile)
pkg/client/library/push.go:	f, err := os.Open(filePath)
pkg/sypgp/sypgp.go:	f, err := os.Open(SecretPath())
pkg/sypgp/sypgp.go:	f, err := os.Open(PublicPath())
pkg/sypgp/sypgp.go:	f, err := os.Open(path)

These were removed:

internal/pkg/build/assemblers/assembler_sif.go:	fp, err := os.Open(parinput.Fname)
internal/pkg/build/build.go:	defFile, err := os.Open(spec)
internal/pkg/build/build.go:	defFile, err := os.Open(spec)
internal/pkg/build/sources/conveyorPacker_arch_test.go:	defFile, err := os.Open(archDef)
internal/pkg/build/sources/conveyorPacker_arch_test.go:	defFile, err := os.Open(archDef)
internal/pkg/build/sources/conveyorPacker_oci.go:	f, err := os.Open(src)
internal/pkg/build/sources/conveyorPacker_busybox_test.go:	defFile, err := os.Open(busyBoxDef)
internal/pkg/build/sources/conveyorPacker_busybox_test.go:	defFile, err := os.Open(busyBoxDef)
internal/pkg/build/sources/conveyorPacker_yum_test.go:	defFile, err := os.Open(yumDef)
internal/pkg/build/sources/conveyorPacker_yum_test.go:	defFile, err := os.Open(yumDef)
internal/pkg/build/sources/conveyorPacker_zypper_test.go:	defFile, err := os.Open(zyppDef)
internal/pkg/build/sources/conveyorPacker_zypper_test.go:	defFile, err := os.Open(zyppDef)
internal/pkg/build/sources/conveyorPacker_scratch_test.go:	defFile, err := os.Open(scratchDef)
internal/pkg/build/sources/conveyorPacker_scratch_test.go:	defFile, err := os.Open(scratchDef)
internal/pkg/build/metadata.go:		jsonFile, err := os.Open(filepath.Join(b.Rootfs(), "/.singularity.d/labels.json"))
pkg/build/legacy/parser/deffile.go:	defFile, err := os.Open(source)
pkg/build/legacy/parser/deffile_test.go:			r, err := os.Open(deffile)
pkg/build/legacy/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/legacy/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/types/parser/deffile.go:	defFile, err := os.Open(source)
pkg/build/types/parser/deffile_test.go:			r, err := os.Open(deffile)
pkg/build/types/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/types/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/types/parser/deffile_test.go:			defFile, err := os.Open(tt.defPath)
pkg/build/types/definition_test.go:	f, err := os.Open(singularityJSON)

It still might not be a bad idea to apply the same checking/updating process to those which we remove, but it's more important to first improve the pieces of our code base which will potentially be run in a suid context.

bauerm97 avatar Apr 22 '19 21:04 bauerm97

This seems like something that would be a good idea to add as a linter to our CI. What do you think?

jscook2345 avatar Jun 14 '19 03:06 jscook2345

Hello,

This is a templated response that is being sent out to all open issues. We are working hard on 'rebuilding' the Singularity community, and a major task on the agenda is finding out what issues are still outstanding.

Please consider the following:

  1. Is this issue a duplicate, or has it been fixed/implemented since being added?
  2. Is the issue still relevant to the current state of Singularity's functionality?
  3. Would you like to continue discussing this issue or feature request?

Thanks, Carter

carterpeel avatar May 15 '21 16:05 carterpeel

This issue has been automatically marked as stale because it has not had activity in over 60 days. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jul 14 '21 16:07 stale[bot]

@bauerm97 Still getting this problem ? Have this been solved already ? If yes, what work around have you followed and applied ?

We're looking into the issue carefully, soon will bring to community and discuss ways to better solve as well address this. Thankyou for keeping the interest in the subject.

pedroalvesbatista avatar Jul 15 '21 06:07 pedroalvesbatista

Copied to https://github.com/apptainer/apptainer/issues/791

kmuriki avatar Oct 17 '22 03:10 kmuriki