@@ -252,16 +252,146 @@ func TestProcOvermountSubdir_ProcThreadSelf(t *testing.T) {
252252 })
253253}
254254
255+ // isFsopenRoot returns whether the internal procfs handle is an fsopen root.
256+ func isFsopenRoot (t * testing.T ) bool {
257+ procRoot , err := getProcRoot ()
258+ require .NoError (t , err )
259+ return procRoot .Name () == "fsmount:fscontext:proc"
260+ }
261+
255262// Because of the introduction of protections against /proc overmounts,
256263// ProcThreadSelf will not be called in actual tests unless we have a basic
257264// test here.
258265func TestProcThreadSelf (t * testing.T ) {
259266 withWithoutOpenat2 (t , true , func (t * testing.T ) {
260- handle , closer , err := ProcThreadSelf ("stat" )
261- require .NoError (t , err , "ProcThreadSelf(stat)" )
262- require .NotNil (t , handle , "ProcThreadSelf(stat)" )
263- defer closer ()
264- defer handle .Close () //nolint:errcheck // test code
267+ t .Run ("stat" , func (t * testing.T ) {
268+ handle , closer , err := ProcThreadSelf ("stat" )
269+ require .NoError (t , err , "ProcThreadSelf(stat)" )
270+ require .NotNil (t , handle , "ProcThreadSelf(stat) handle" )
271+ require .NotNil (t , closer , "ProcThreadSelf(stat) closer" )
272+ defer closer ()
273+ defer handle .Close () //nolint:errcheck // test code
274+
275+ realPath , err := ProcSelfFdReadlink (handle )
276+ require .NoError (t , err )
277+ wantPath := fmt .Sprintf ("/%d/task/%d/stat" , os .Getpid (), unix .Gettid ())
278+ if ! isFsopenRoot (t ) {
279+ // The /proc prefix is only present when not using fsopen.
280+ wantPath = "/proc" + wantPath
281+ }
282+ assert .Equal (t , wantPath , realPath , "final handle path" )
283+ })
284+
285+ t .Run ("abspath" , func (t * testing.T ) {
286+ handle , closer , err := ProcThreadSelf ("/stat" )
287+ require .NoError (t , err , "ProcThreadSelf(/stat)" )
288+ require .NotNil (t , handle , "ProcThreadSelf(/stat) handle" )
289+ require .NotNil (t , closer , "ProcThreadSelf(/stat) closer" )
290+ defer closer ()
291+ defer handle .Close () //nolint:errcheck // test code
292+
293+ realPath , err := ProcSelfFdReadlink (handle )
294+ require .NoError (t , err )
295+ wantPath := fmt .Sprintf ("/%d/task/%d/stat" , os .Getpid (), unix .Gettid ())
296+ if ! isFsopenRoot (t ) {
297+ // The /proc prefix is only present when not using fsopen.
298+ wantPath = "/proc" + wantPath
299+ }
300+ assert .Equal (t , wantPath , realPath , "final handle path" )
301+ })
302+
303+ t .Run ("wacky-abspath" , func (t * testing.T ) {
304+ handle , closer , err := ProcThreadSelf ("////./////stat" )
305+ require .NoError (t , err , "ProcThreadSelf(////./////stat)" )
306+ require .NotNil (t , handle , "ProcThreadSelf(////./////stat) handle" )
307+ require .NotNil (t , closer , "ProcThreadSelf(////./////stat) closer" )
308+ defer closer ()
309+ defer handle .Close () //nolint:errcheck // test code
310+
311+ realPath , err := ProcSelfFdReadlink (handle )
312+ require .NoError (t , err )
313+ wantPath := fmt .Sprintf ("/%d/task/%d/stat" , os .Getpid (), unix .Gettid ())
314+ if ! isFsopenRoot (t ) {
315+ // The /proc prefix is only present when not using fsopen.
316+ wantPath = "/proc" + wantPath
317+ }
318+ assert .Equal (t , wantPath , realPath , "final handle path" )
319+ })
320+
321+ t .Run ("dotdot" , func (t * testing.T ) {
322+ handle , closer , err := ProcThreadSelf ("../../../../../../../../.." )
323+ require .Error (t , err , "ProcThreadSelf(../...)" )
324+ require .Nil (t , handle , "ProcThreadSelf(../...) handle" )
325+ require .Nil (t , closer , "ProcThreadSelf(../...) closer" )
326+ })
327+
328+ t .Run ("wacky-dotdot" , func (t * testing.T ) {
329+ handle , closer , err := ProcThreadSelf ("/../../../../../../../../.." )
330+ require .Error (t , err , "ProcThreadSelf(/../...)" )
331+ require .Nil (t , handle , "ProcThreadSelf(/../...) handle" )
332+ require .Nil (t , closer , "ProcThreadSelf(/../...) closer" )
333+ })
334+ })
335+ }
336+
337+ func TestProcPid (t * testing.T ) {
338+ withWithoutOpenat2 (t , true , func (t * testing.T ) {
339+ t .Run ("pid1-stat" , func (t * testing.T ) {
340+ handle , err := ProcPid (1 , "stat" )
341+ require .NoError (t , err , "ProcPid(1, stat)" )
342+ require .NotNil (t , handle , "ProcPid(1, stat) handle" )
343+
344+ realPath , err := ProcSelfFdReadlink (handle )
345+ require .NoError (t , err )
346+ wantPath := "/1/stat"
347+ if ! isFsopenRoot (t ) {
348+ // The /proc prefix is only present when not using fsopen.
349+ wantPath = "/proc" + wantPath
350+ }
351+ assert .Equal (t , wantPath , realPath , "final handle path" )
352+ })
353+
354+ t .Run ("pid1-stat-abspath" , func (t * testing.T ) {
355+ handle , err := ProcPid (1 , "/stat" )
356+ require .NoError (t , err , "ProcPid(1, /stat)" )
357+ require .NotNil (t , handle , "ProcPid(1, /stat) handle" )
358+
359+ realPath , err := ProcSelfFdReadlink (handle )
360+ require .NoError (t , err )
361+ wantPath := "/1/stat"
362+ if ! isFsopenRoot (t ) {
363+ // The /proc prefix is only present when not using fsopen.
364+ wantPath = "/proc" + wantPath
365+ }
366+ assert .Equal (t , wantPath , realPath , "final handle path" )
367+ })
368+
369+ t .Run ("pid1-stat-wacky-abspath" , func (t * testing.T ) {
370+ handle , err := ProcPid (1 , "////.////stat" )
371+ require .NoError (t , err , "ProcPid(1, ////.////stat)" )
372+ require .NotNil (t , handle , "ProcPid(1, ////.////stat) handle" )
373+
374+ realPath , err := ProcSelfFdReadlink (handle )
375+ require .NoError (t , err )
376+ wantPath := "/1/stat"
377+ if ! isFsopenRoot (t ) {
378+ // The /proc prefix is only present when not using fsopen.
379+ wantPath = "/proc" + wantPath
380+ }
381+ assert .Equal (t , wantPath , realPath , "final handle path" )
382+ })
383+
384+ t .Run ("dotdot" , func (t * testing.T ) {
385+ handle , err := ProcPid (1 , "../../../../../../../../.." )
386+ require .Error (t , err , "ProcPid(1, ../...)" )
387+ require .Nil (t , handle , "ProcPid(1, ../...) handle" )
388+ })
389+
390+ t .Run ("wacky-dotdot" , func (t * testing.T ) {
391+ handle , err := ProcPid (1 , "/../../../../../../../../.." )
392+ require .Error (t , err , "ProcPid(1, /../...)" )
393+ require .Nil (t , handle , "ProcPid(1, /../...) handle" )
394+ })
265395 })
266396}
267397
0 commit comments