@@ -252,6 +252,13 @@ 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.
@@ -267,7 +274,11 @@ func TestProcThreadSelf(t *testing.T) {
267274
268275 realPath , err := ProcSelfFdReadlink (handle )
269276 require .NoError (t , err )
270- wantPath := fmt .Sprintf ("/proc/%d/task/%d/stat" , os .Getpid (), unix .Gettid ())
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+ }
271282 assert .Equal (t , wantPath , realPath , "final handle path" )
272283 })
273284
@@ -281,7 +292,11 @@ func TestProcThreadSelf(t *testing.T) {
281292
282293 realPath , err := ProcSelfFdReadlink (handle )
283294 require .NoError (t , err )
284- wantPath := fmt .Sprintf ("/proc/%d/task/%d/stat" , os .Getpid (), unix .Gettid ())
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+ }
285300 assert .Equal (t , wantPath , realPath , "final handle path" )
286301 })
287302
@@ -295,7 +310,11 @@ func TestProcThreadSelf(t *testing.T) {
295310
296311 realPath , err := ProcSelfFdReadlink (handle )
297312 require .NoError (t , err )
298- wantPath := fmt .Sprintf ("/proc/%d/task/%d/stat" , os .Getpid (), unix .Gettid ())
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+ }
299318 assert .Equal (t , wantPath , realPath , "final handle path" )
300319 })
301320
@@ -315,6 +334,67 @@ func TestProcThreadSelf(t *testing.T) {
315334 })
316335}
317336
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+ })
395+ })
396+ }
397+
318398func canFsOpen () bool {
319399 f , err := fsopen ("tmpfs" , 0 )
320400 if f != nil {
0 commit comments