Message ID | 20220517140748.24238-1-cgzones@googlemail.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Series | [1/2] libselinux: restorecon: add fallback for pre 3.6 Linux | expand |
On Tue, May 17, 2022 at 12:58 PM Christian Göttsche <cgzones@googlemail.com> wrote: > > fstat(2) on file descriptors obtained via O_PATH is supported since > Linux 3.6. Fallback on older systems to lstat(2). > > Fixes: 7e979b56 ("libselinux: restorecon: pin file to avoid TOCTOU issues") > > Signed-off-by: Christian Göttsche <cgzones@googlemail.com> > --- > libselinux/src/selinux_restorecon.c | 29 +++++++++++++++++++++++++---- > 1 file changed, 25 insertions(+), 4 deletions(-) > > diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c > index 9dd6be81..1a185ced 100644 > --- a/libselinux/src/selinux_restorecon.c > +++ b/libselinux/src/selinux_restorecon.c > @@ -89,10 +89,22 @@ struct rest_flags { > bool count_errors; > }; > > +/* Linux version for availability tests. */ > +static struct utsname uts; > + > static void restorecon_init(void) > { > struct selabel_handle *sehandle = NULL; > > + if (uname(&uts) < 0) { > + /* > + * utsname(2) should never fail, but assume oldest supported Should be "uname(2) should ..." > + * LTS release as backup > + */ > + strncpy(uts.release, "4.9", sizeof(uts.release)); I don't know. Using 4.9 seems arbitrary. I think that I would prefer just using "3.6" and note that only behavior is only changed for kernels prior to 3.6 or something like that. Thanks, Jim > + uts.release[sizeof(uts.release) - 1] = '\0'; > + } > + > if (!fc_sehandle) { > sehandle = selinux_restorecon_default_handle(); > selinux_restorecon_set_sehandle(sehandle); > @@ -238,7 +250,6 @@ static uint64_t file_system_count(const char *name) > */ > static uint64_t exclude_non_seclabel_mounts(void) > { > - struct utsname uts; > FILE *fp; > size_t len; > int index = 0, found = 0; > @@ -247,7 +258,7 @@ static uint64_t exclude_non_seclabel_mounts(void) > char *buf = NULL, *item; > > /* Check to see if the kernel supports seclabel */ > - if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0) > + if (strverscmp(uts.release, "2.6.30") < 0) > return 0; > if (is_selinux_enabled() <= 0) > return 0; > @@ -648,9 +659,19 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi > if (fd < 0) > goto err; > > + /* > + * fstat(2) on file descriptors obtained via O_PATH are supported > + * since Linux 3.6, see man:open(2). > + * Test fstat(2) first, support might have been backported. > + */ > rc = fstat(fd, &stat_buf); > - if (rc < 0) > - goto err; > + if (rc < 0) { > + if (errno == EBADF && strverscmp(uts.release, "3.6") < 0) > + rc = lstat(pathname, &stat_buf); > + > + if (rc < 0) > + goto err; > + } > > if (rootpath != NULL && lookup_path[0] == '\0') > /* this is actually the root dir of the alt root. */ > -- > 2.36.1 >
diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c index 9dd6be81..1a185ced 100644 --- a/libselinux/src/selinux_restorecon.c +++ b/libselinux/src/selinux_restorecon.c @@ -89,10 +89,22 @@ struct rest_flags { bool count_errors; }; +/* Linux version for availability tests. */ +static struct utsname uts; + static void restorecon_init(void) { struct selabel_handle *sehandle = NULL; + if (uname(&uts) < 0) { + /* + * utsname(2) should never fail, but assume oldest supported + * LTS release as backup + */ + strncpy(uts.release, "4.9", sizeof(uts.release)); + uts.release[sizeof(uts.release) - 1] = '\0'; + } + if (!fc_sehandle) { sehandle = selinux_restorecon_default_handle(); selinux_restorecon_set_sehandle(sehandle); @@ -238,7 +250,6 @@ static uint64_t file_system_count(const char *name) */ static uint64_t exclude_non_seclabel_mounts(void) { - struct utsname uts; FILE *fp; size_t len; int index = 0, found = 0; @@ -247,7 +258,7 @@ static uint64_t exclude_non_seclabel_mounts(void) char *buf = NULL, *item; /* Check to see if the kernel supports seclabel */ - if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0) + if (strverscmp(uts.release, "2.6.30") < 0) return 0; if (is_selinux_enabled() <= 0) return 0; @@ -648,9 +659,19 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi if (fd < 0) goto err; + /* + * fstat(2) on file descriptors obtained via O_PATH are supported + * since Linux 3.6, see man:open(2). + * Test fstat(2) first, support might have been backported. + */ rc = fstat(fd, &stat_buf); - if (rc < 0) - goto err; + if (rc < 0) { + if (errno == EBADF && strverscmp(uts.release, "3.6") < 0) + rc = lstat(pathname, &stat_buf); + + if (rc < 0) + goto err; + } if (rootpath != NULL && lookup_path[0] == '\0') /* this is actually the root dir of the alt root. */
fstat(2) on file descriptors obtained via O_PATH is supported since Linux 3.6. Fallback on older systems to lstat(2). Fixes: 7e979b56 ("libselinux: restorecon: pin file to avoid TOCTOU issues") Signed-off-by: Christian Göttsche <cgzones@googlemail.com> --- libselinux/src/selinux_restorecon.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-)