@@ -414,72 +414,91 @@ bind_mount (int proc_fd,
414414 return BIND_MOUNT_ERROR_REOPEN_DEST ;
415415 }
416416
417- /* If we are in a case-insensitive filesystem, mountinfo might contain a
418- * different case combination of the path we requested to mount.
419- * This is due to the fact that the kernel, as of the beginning of 2021,
420- * populates mountinfo with whatever case combination first appeared in the
421- * dcache; kernel developers plan to change this in future so that it
422- * reflects the on-disk encoding instead.
423- * To avoid throwing an error when this happens, we use readlink() result
424- * instead of the provided @root_mount, so that we can compare the mountinfo
425- * entries with the same case combination that the kernel is expected to
426- * use. */
427- dest_proc = xasprintf ("/proc/self/fd/%d" , dest_fd );
428- oldroot_dest_proc = get_oldroot_path (dest_proc );
429- kernel_case_combination = readlink_malloc (oldroot_dest_proc );
430- if (kernel_case_combination == NULL )
417+ if (has_mount_setattr ())
431418 {
432- if (failing_path != NULL )
433- * failing_path = steal_pointer (& resolved_dest );
434-
435- return BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD ;
419+ struct mount_attr attr = {
420+ .attr_clr = 0 ,
421+ .attr_set = MOUNT_ATTR_NOSUID | (devices ? 0 : MOUNT_ATTR_NODEV ) |
422+ (readonly ? MOUNT_ATTR_RDONLY : 0 ),
423+ };
424+ if (mount_setattr (dest_fd , "" ,
425+ AT_EMPTY_PATH | (recursive ? AT_RECURSIVE : 0 ), & attr ,
426+ sizeof (attr )) == -1 )
427+ {
428+ if (failing_path != NULL )
429+ * failing_path = steal_pointer (& resolved_dest );
430+ return BIND_MOUNT_ERROR_MOUNT_SETATTR ;
431+ }
436432 }
437-
438- mount_tab = parse_mountinfo (proc_fd , kernel_case_combination );
439- if (mount_tab [0 ].mountpoint == NULL )
433+ else
440434 {
441- if (failing_path != NULL )
442- * failing_path = steal_pointer (& kernel_case_combination );
435+ /* If we are in a case-insensitive filesystem, mountinfo might contain a
436+ * different case combination of the path we requested to mount.
437+ * This is due to the fact that the kernel, as of the beginning of 2021,
438+ * populates mountinfo with whatever case combination first appeared in the
439+ * dcache; kernel developers plan to change this in future so that it
440+ * reflects the on-disk encoding instead.
441+ * To avoid throwing an error when this happens, we use readlink() result
442+ * instead of the provided @root_mount, so that we can compare the mountinfo
443+ * entries with the same case combination that the kernel is expected to
444+ * use. */
445+ dest_proc = xasprintf ("/proc/self/fd/%d" , dest_fd );
446+ oldroot_dest_proc = get_oldroot_path (dest_proc );
447+ kernel_case_combination = readlink_malloc (oldroot_dest_proc );
448+ if (kernel_case_combination == NULL )
449+ {
450+ if (failing_path != NULL )
451+ * failing_path = steal_pointer (& resolved_dest );
443452
444- errno = EINVAL ;
445- return BIND_MOUNT_ERROR_FIND_DEST_MOUNT ;
446- }
453+ return BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD ;
454+ }
447455
448- assert (path_equal (mount_tab [0 ].mountpoint , kernel_case_combination ));
449- current_flags = mount_tab [0 ].options ;
450- new_flags = current_flags | (devices ? 0 : MS_NODEV ) | MS_NOSUID | (readonly ? MS_RDONLY : 0 );
451- if (new_flags != current_flags &&
452- mount ("none" , resolved_dest ,
453- NULL , MS_SILENT | MS_BIND | MS_REMOUNT | new_flags , NULL ) != 0 )
454- {
455- if (failing_path != NULL )
456- * failing_path = steal_pointer (& resolved_dest );
456+ mount_tab = parse_mountinfo (proc_fd , kernel_case_combination );
457+ if (mount_tab [0 ].mountpoint == NULL )
458+ {
459+ if (failing_path != NULL )
460+ * failing_path = steal_pointer (& kernel_case_combination );
457461
458- return BIND_MOUNT_ERROR_REMOUNT_DEST ;
459- }
462+ errno = EINVAL ;
463+ return BIND_MOUNT_ERROR_FIND_DEST_MOUNT ;
464+ }
460465
461- /* We need to work around the fact that a bind mount does not apply the flags, so we need to manually
462- * apply the flags to all submounts in the recursive case.
463- * Note: This does not apply the flags to mounts which are later propagated into this namespace.
464- */
465- if (recursive )
466- {
467- for (i = 1 ; mount_tab [i ].mountpoint != NULL ; i ++ )
466+ assert (path_equal (mount_tab [0 ].mountpoint , kernel_case_combination ));
467+ current_flags = mount_tab [0 ].options ;
468+ new_flags = current_flags | (devices ? 0 : MS_NODEV ) | MS_NOSUID | (readonly ? MS_RDONLY : 0 );
469+ if (new_flags != current_flags &&
470+ mount ("none" , resolved_dest ,
471+ NULL , MS_SILENT | MS_BIND | MS_REMOUNT | new_flags , NULL ) != 0 )
472+ {
473+ if (failing_path != NULL )
474+ * failing_path = steal_pointer (& resolved_dest );
475+
476+ return BIND_MOUNT_ERROR_REMOUNT_DEST ;
477+ }
478+
479+ /* We need to work around the fact that a bind mount does not apply the flags, so we need to manually
480+ * apply the flags to all submounts in the recursive case.
481+ * Note: This does not apply the flags to mounts which are later propagated into this namespace.
482+ */
483+ if (recursive )
468484 {
469- current_flags = mount_tab [i ].options ;
470- new_flags = current_flags | (devices ? 0 : MS_NODEV ) | MS_NOSUID | (readonly ? MS_RDONLY : 0 );
471- if (new_flags != current_flags &&
472- mount ("none" , mount_tab [i ].mountpoint ,
473- NULL , MS_SILENT | MS_BIND | MS_REMOUNT | new_flags , NULL ) != 0 )
485+ for (i = 1 ; mount_tab [i ].mountpoint != NULL ; i ++ )
474486 {
475- /* If we can't read the mountpoint we can't remount it, but that should
476- be safe to ignore because its not something the user can access. */
477- if (errno != EACCES )
487+ current_flags = mount_tab [i ].options ;
488+ new_flags = current_flags | (devices ? 0 : MS_NODEV ) | MS_NOSUID | (readonly ? MS_RDONLY : 0 );
489+ if (new_flags != current_flags &&
490+ mount ("none" , mount_tab [i ].mountpoint ,
491+ NULL , MS_SILENT | MS_BIND | MS_REMOUNT | new_flags , NULL ) != 0 )
478492 {
479- if (failing_path != NULL )
480- * failing_path = xstrdup (mount_tab [i ].mountpoint );
481-
482- return BIND_MOUNT_ERROR_REMOUNT_SUBMOUNT ;
493+ /* If we can't read the mountpoint we can't remount it, but that should
494+ be safe to ignore because its not something the user can access. */
495+ if (errno != EACCES )
496+ {
497+ if (failing_path != NULL )
498+ * failing_path = xstrdup (mount_tab [i ].mountpoint );
499+
500+ return BIND_MOUNT_ERROR_REMOUNT_SUBMOUNT ;
501+ }
483502 }
484503 }
485504 }
@@ -534,6 +553,10 @@ bind_mount_result_to_string (bind_mount_result res,
534553 failing_path );
535554 break ;
536555
556+ case BIND_MOUNT_ERROR_MOUNT_SETATTR :
557+ string = xasprintf ("mount_setattr() failed at \"%s\"" , failing_path );
558+ break ;
559+
537560 case BIND_MOUNT_SUCCESS :
538561 string = xstrdup ("Success" );
539562 break ;
@@ -587,6 +610,7 @@ die_with_bind_result (bind_mount_result res,
587610 case BIND_MOUNT_ERROR_REOPEN_DEST :
588611 case BIND_MOUNT_ERROR_READLINK_DEST_PROC_FD :
589612 case BIND_MOUNT_ERROR_FIND_DEST_MOUNT :
613+ case BIND_MOUNT_ERROR_MOUNT_SETATTR :
590614 case BIND_MOUNT_SUCCESS :
591615 default :
592616 fprintf (stderr , ": %s" , strerror (saved_errno ));
0 commit comments