File: procfs-open.bats

package info (click to toggle)
rust-pathrs 0.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,912 kB
  • sloc: python: 1,138; sh: 371; ansic: 259; makefile: 151
file content (207 lines) | stat: -rw-r--r-- 6,455 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#!/usr/bin/bats -t
# SPDX-License-Identifier: MPL-2.0
#
# libpathrs: safe path resolution on Linux
# Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
# Copyright (C) 2019-2025 SUSE LLC
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

load helpers

function setup() {
	setup_tmpdirs
}

function teardown() {
	teardown_tmpdirs
}

# TODO: All of these tests are very limited because we cannot verify anything
# useful about the opened files (and the path is actually not guaranteed to be
# correct outside of magic-link cases). Ideally we would instead output
# something simple like the fdinfo, stat, and/or contents to verify against.

@test "procfs --base open --oflags O_RDONLY" {
	pathrs-cmd procfs open modules
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/modules$' <<<"$output"

	pathrs-cmd procfs --base root open --oflags O_RDONLY modules
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/modules$' <<<"$output"
}

@test "procfs --base pid=\$\$ --oflags O_RDONLY" {
	pathrs-cmd procfs open modules
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/modules$' <<<"$output"

	pathrs-cmd procfs --base root open --oflags O_RDONLY modules
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/modules$' <<<"$output"
}

@test "procfs --base self --oflags O_RDONLY" {
	pathrs-cmd procfs --base self open status
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+/status$' <<<"$output"

	pathrs-cmd procfs --base self open stack
	[ "$status" -eq 0 ]
	# NOTE: While only admins can read from /proc/$n/stack, we can open it.
	grep -E '^FILE-PATH (/proc)?/[0-9]+/stack$' <<<"$output"
}

@test "procfs --base thread-self --oflags O_RDONLY" {
	pathrs-cmd procfs --base thread-self open status
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+/task/[0-9]+/status$' <<<"$output"

	pathrs-cmd procfs --base thread-self open stack
	[ "$status" -eq 0 ]
	# NOTE: While only admins can read from /proc/$n/stack, we can open it.
	grep -E '^FILE-PATH (/proc)?/[0-9]+/task/[0-9]+/stack$' <<<"$output"
}

# Make sure that thread-self and self are actually handled differently.
@test "procfs open [self != thread-self]" {
	pathrs-cmd procfs --base self open task
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]*/task$' <<<"$output"

	pathrs-cmd procfs --base thread-self open task
	check-errno ENOENT
}

@test "procfs open --follow [symlinks]" {
	pathrs-cmd procfs open mounts
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+/mounts$' <<<"$output"

	pathrs-cmd procfs open --oflags O_DIRECTORY mounts
	check-errno ENOTDIR

	pathrs-cmd procfs open --oflags O_DIRECTORY net
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+/net$' <<<"$output"

	pathrs-cmd procfs open --follow self
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+$' <<<"$output"

	pathrs-cmd procfs open --follow thread-self
	if [ -e /proc/thread-self ]; then
		[ "$status" -eq 0 ]
		grep -E '^FILE-PATH (/proc)?/[0-9]+/task/[0-9]+$' <<<"$output"
	else
		check-errno ENOENT
	fi
}

@test "procfs open --follow [magic-links]" {
	exepath="$(readlink -f "$PATHRS_CMD")"

	pathrs-cmd procfs --base self open --follow --oflags O_RDONLY exe
	[ "$status" -eq 0 ]
	! grep -E '^FILE-PATH (/proc)?/[0-9]+/.*$' <<<"$output"
	# We can only guess /proc/self/exe for compiled pathrs-cmd binaries.
	if is-compiled "$PATHRS_CMD"; then
		grep -Fx "FILE-PATH $exepath" <<<"$output"
	fi

	realpwd="$(readlink -f "$PWD")"

	pathrs-cmd procfs --base self open --follow --oflags O_RDONLY cwd
	[ "$status" -eq 0 ]
	grep -Fx "FILE-PATH $realpwd" <<<"$output"

	dummyfile="$(setup_tmpdir)/dummyfile"
	echo "THIS SHOULD BE TRUNCATED" >"$dummyfile"
	[ "$(stat -c '%s' "$dummyfile")" -ne 0 ]

	pathrs-cmd procfs --base thread-self open --follow --oflags O_RDWR,O_TRUNC fd/100 100>>"$dummyfile"
	[ "$status" -eq 0 ]
	grep -Fx "FILE-PATH $dummyfile" <<<"$output"
	# The file should've been truncated by O_TRUNC.
	[ "$(stat -c '%s' "$dummyfile")" -eq 0 ]
}

@test "procfs open --no-follow [symlinks]" {
	pathrs-cmd procfs open --no-follow mounts
	check-errno ELOOP

	pathrs-cmd procfs open --no-follow net
	check-errno ELOOP

	pathrs-cmd procfs open --no-follow self
	check-errno ELOOP

	pathrs-cmd procfs open --no-follow thread-self
	if [ -e /proc/thread-self ]; then
		check-errno ELOOP
	else
		check-errno ENOENT
	fi
}

@test "procfs open --no-follow [magic-links]" {
	pathrs-cmd procfs --base pid=1 open --no-follow --oflags O_DIRECTORY root
	# O_DIRECTORY beats O_NOFOLLOW!
	check-errno ENOTDIR

	pathrs-cmd procfs --base pid=1 open --no-follow --oflags O_RDWR root
	# O_NOFOLLOW beats permission errors
	check-errno ELOOP

	pathrs-cmd procfs --base self open --no-follow --oflags O_RDONLY exe
	check-errno ELOOP

	pathrs-cmd procfs --base thread-self open --no-follow --oflags O_RDONLY exe
	check-errno ELOOP

	dummyfile="$(setup_tmpdir)/dummyfile"
	echo "THIS SHOULD NOT BE TRUNCATED" >"$dummyfile"
	[ "$(stat -c '%s' "$dummyfile")" -ne 0 ]

	pathrs-cmd procfs --base thread-self open --no-follow --oflags O_RDWR,O_TRUNC fd/100 100>>"$dummyfile"
	check-errno ELOOP
	# The file should NOT have been truncated by O_TRUNC.
	[ "$(stat -c '%s' "$dummyfile")" -ne 0 ]
}

@test "procfs open --no-follow --oflags O_PATH [symlinks]" {
	pathrs-cmd procfs --base self open --no-follow --oflags O_PATH exe
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+/exe$' <<<"$output"

	pathrs-cmd procfs --base pid=$$ open --oflags O_PATH,O_NOFOLLOW exe
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/'"$$"'/exe$' <<<"$output"

	pathrs-cmd procfs --base thread-self open --oflags O_PATH,O_NOFOLLOW exe
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+/task/[0-9]+/exe$' <<<"$output"
}

@test "procfs open [symlink parent component]" {
	pathrs-cmd procfs --base root open self/status
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+/status$' <<<"$output"

	pathrs-cmd procfs --base root open self/fdinfo/0
	[ "$status" -eq 0 ]
	grep -E '^FILE-PATH (/proc)?/[0-9]+/fdinfo/0$' <<<"$output"

	exepath="$(readlink -f "$PATHRS_CMD")"

	pathrs-cmd procfs --base root open self/exe
	[ "$status" -eq 0 ]
	! grep -E '^FILE-PATH (/proc)?/[0-9]+/.*$' <<<"$output"
	# We can only guess /proc/self/exe for compiled pathrs-cmd binaries.
	if is-compiled "$PATHRS_CMD"; then
		grep -Fx "FILE-PATH $exepath" <<<"$output"
	fi
}