1212/* See the License for the specific language governing permissions and */
1313/* limitations under the License. */
1414
15+ /* LD_PRELOAD shim that denies HAProxy access to the Kubernetes service-account
16+ token dir (default /var/run/secrets/kubernetes.io). Interposes the libc
17+ calls that read or mutate a path and returns EACCES for anything resolving
18+ inside it. Metadata-only calls (stat/access/readlink) are deliberately NOT
19+ hooked so they stay off HAProxy's hot path (issue #818). */
20+
1521#define _XOPEN_SOURCE 700
1622
17- #include <dirent.h>
1823#include <dlfcn.h>
1924#include <errno.h>
2025#include <fcntl.h>
3439/* Forward-declared to avoid _GNU_SOURCE, which on musl macro-aliases the
3540 *64 stat names and would collide with our hook symbols. */
3641struct file_handle ;
37- struct statx ;
3842
3943#ifndef PATH_MAX
4044#define PATH_MAX 4096
@@ -54,7 +58,7 @@ static char text_blocked[PATH_MAX] = {0};
5458static size_t text_blocked_len = 0 ;
5559static int text_canonical_same = 1 ;
5660
57- /* Recursion guard: musl's realpath() uses the public readlink symbol
61+ /* Recursion guard: realpath() resolves paths via the public open() symbol,
5862 which our hook would otherwise re-enter. */
5963static __thread int in_is_blocked = 0 ;
6064
@@ -218,21 +222,6 @@ static int (*real_creat)(const char *, mode_t) = NULL;
218222static int (* real_creat64 )(const char * , mode_t ) = NULL ;
219223static int (* real_openat )(int , const char * , int , ...) = NULL ;
220224static int (* real_openat64 )(int , const char * , int , ...) = NULL ;
221- static int (* real_access )(const char * , int ) = NULL ;
222- static int (* real_faccessat )(int , const char * , int , int ) = NULL ;
223- static ssize_t (* real_readlink )(const char * , char * , size_t ) = NULL ;
224- static ssize_t (* real_readlinkat )(int , const char * , char * , size_t ) = NULL ;
225- static DIR * (* real_opendir )(const char * ) = NULL ;
226- static int (* real_stat )(const char * , struct stat * ) = NULL ;
227- static int (* real_lstat )(const char * , struct stat * ) = NULL ;
228- static int (* real_fstatat )(int , const char * , struct stat * , int ) = NULL ;
229- /* void * avoids _LARGEFILE64_SOURCE, which on musl macro-aliases stat64
230- to stat and would break our hook symbol. */
231- static int (* real_stat64 )(const char * , void * ) = NULL ;
232- static int (* real_lstat64 )(const char * , void * ) = NULL ;
233- static int (* real_fstatat64 )(int , const char * , void * , int ) = NULL ;
234- static int (* real_statx )(int , const char * , int , unsigned int ,
235- struct statx * ) = NULL ;
236225static int (* real_name_to_handle_at )(int , const char * , struct file_handle * ,
237226 int * , int ) = NULL ;
238227static int (* real_mkdir )(const char * , mode_t ) = NULL ;
@@ -276,18 +265,6 @@ __attribute__((constructor(101), cold)) static void block_secrets_init(void) {
276265 real_creat64 = dlsym (RTLD_NEXT , "creat64" );
277266 real_openat = dlsym (RTLD_NEXT , "openat" );
278267 real_openat64 = dlsym (RTLD_NEXT , "openat64" );
279- real_access = dlsym (RTLD_NEXT , "access" );
280- real_faccessat = dlsym (RTLD_NEXT , "faccessat" );
281- real_readlink = dlsym (RTLD_NEXT , "readlink" );
282- real_readlinkat = dlsym (RTLD_NEXT , "readlinkat" );
283- real_opendir = dlsym (RTLD_NEXT , "opendir" );
284- real_stat = dlsym (RTLD_NEXT , "stat" );
285- real_lstat = dlsym (RTLD_NEXT , "lstat" );
286- real_fstatat = dlsym (RTLD_NEXT , "fstatat" );
287- real_stat64 = dlsym (RTLD_NEXT , "stat64" );
288- real_lstat64 = dlsym (RTLD_NEXT , "lstat64" );
289- real_fstatat64 = dlsym (RTLD_NEXT , "fstatat64" );
290- real_statx = dlsym (RTLD_NEXT , "statx" );
291268 real_name_to_handle_at = dlsym (RTLD_NEXT , "name_to_handle_at" );
292269 real_mkdir = dlsym (RTLD_NEXT , "mkdir" );
293270 real_mkdirat = dlsym (RTLD_NEXT , "mkdirat" );
@@ -314,6 +291,28 @@ __attribute__((constructor(101), cold)) static void block_secrets_init(void) {
314291 real_symlink = dlsym (RTLD_NEXT , "symlink" );
315292 real_symlinkat = dlsym (RTLD_NEXT , "symlinkat" );
316293
294+ /* musl exports no distinct LFS64 symbols, so the dlsym()s above leave these
295+ NULL. off_t is 64-bit on every supported ABI, so *64 == base: alias them.
296+ Otherwise the exported *64 hooks would return ENOSYS (issue #818). */
297+ if (real_open64 == NULL ) {
298+ real_open64 = real_open ;
299+ }
300+ if (real_fopen64 == NULL ) {
301+ real_fopen64 = real_fopen ;
302+ }
303+ if (real_freopen64 == NULL ) {
304+ real_freopen64 = real_freopen ;
305+ }
306+ if (real_creat64 == NULL ) {
307+ real_creat64 = real_creat ;
308+ }
309+ if (real_openat64 == NULL ) {
310+ real_openat64 = real_openat ;
311+ }
312+ if (real_truncate64 == NULL ) {
313+ real_truncate64 = (int (* )(const char * , int64_t ))real_truncate ;
314+ }
315+
317316 const char * src = getenv (BLOCKED_PATH_ENV );
318317 if (src == NULL ) {
319318 src = BLOCKED_PATH_DEFAULT ;
@@ -477,119 +476,6 @@ HOOK_VISIBLE int openat64(int dirfd, const char *pathname, int flags, ...) {
477476 return real_openat64 (dirfd , pathname , flags , mode );
478477}
479478
480- HOOK_VISIBLE int access (const char * pathname , int mode ) {
481- if (path_blocked (pathname )) {
482- errno = EACCES ;
483- return -1 ;
484- }
485- HOOK_GUARD (real_access , -1 );
486- return real_access (pathname , mode );
487- }
488-
489- HOOK_VISIBLE int faccessat (int dirfd , const char * pathname , int mode ,
490- int flags ) {
491- if (path_blocked (pathname )) {
492- errno = EACCES ;
493- return -1 ;
494- }
495- HOOK_GUARD (real_faccessat , -1 );
496- return real_faccessat (dirfd , pathname , mode , flags );
497- }
498-
499- HOOK_VISIBLE ssize_t readlink (const char * pathname , char * buf , size_t bufsiz ) {
500- if (path_blocked (pathname )) {
501- errno = EACCES ;
502- return -1 ;
503- }
504- HOOK_GUARD (real_readlink , -1 );
505- return real_readlink (pathname , buf , bufsiz );
506- }
507-
508- HOOK_VISIBLE ssize_t readlinkat (int dirfd , const char * pathname , char * buf ,
509- size_t bufsiz ) {
510- if (path_blocked (pathname )) {
511- errno = EACCES ;
512- return -1 ;
513- }
514- HOOK_GUARD (real_readlinkat , -1 );
515- return real_readlinkat (dirfd , pathname , buf , bufsiz );
516- }
517-
518- HOOK_VISIBLE DIR * opendir (const char * name ) {
519- if (path_blocked (name )) {
520- errno = EACCES ;
521- return NULL ;
522- }
523- HOOK_GUARD (real_opendir , NULL );
524- return real_opendir (name );
525- }
526-
527- HOOK_VISIBLE int stat (const char * pathname , struct stat * buf ) {
528- if (path_blocked (pathname )) {
529- errno = EACCES ;
530- return -1 ;
531- }
532- HOOK_GUARD (real_stat , -1 );
533- return real_stat (pathname , buf );
534- }
535-
536- HOOK_VISIBLE int lstat (const char * pathname , struct stat * buf ) {
537- if (path_blocked (pathname )) {
538- errno = EACCES ;
539- return -1 ;
540- }
541- HOOK_GUARD (real_lstat , -1 );
542- return real_lstat (pathname , buf );
543- }
544-
545- HOOK_VISIBLE int fstatat (int dirfd , const char * pathname , struct stat * buf ,
546- int flags ) {
547- if (path_blocked (pathname )) {
548- errno = EACCES ;
549- return -1 ;
550- }
551- HOOK_GUARD (real_fstatat , -1 );
552- return real_fstatat (dirfd , pathname , buf , flags );
553- }
554-
555- HOOK_VISIBLE int stat64 (const char * pathname , void * buf ) {
556- if (path_blocked (pathname )) {
557- errno = EACCES ;
558- return -1 ;
559- }
560- HOOK_GUARD (real_stat64 , -1 );
561- return real_stat64 (pathname , buf );
562- }
563-
564- HOOK_VISIBLE int lstat64 (const char * pathname , void * buf ) {
565- if (path_blocked (pathname )) {
566- errno = EACCES ;
567- return -1 ;
568- }
569- HOOK_GUARD (real_lstat64 , -1 );
570- return real_lstat64 (pathname , buf );
571- }
572-
573- HOOK_VISIBLE int fstatat64 (int dirfd , const char * pathname , void * buf ,
574- int flags ) {
575- if (path_blocked (pathname )) {
576- errno = EACCES ;
577- return -1 ;
578- }
579- HOOK_GUARD (real_fstatat64 , -1 );
580- return real_fstatat64 (dirfd , pathname , buf , flags );
581- }
582-
583- HOOK_VISIBLE int statx (int dirfd , const char * pathname , int flags ,
584- unsigned int mask , struct statx * buf ) {
585- if (path_blocked (pathname )) {
586- errno = EACCES ;
587- return -1 ;
588- }
589- HOOK_GUARD (real_statx , -1 );
590- return real_statx (dirfd , pathname , flags , mask , buf );
591- }
592-
593479HOOK_VISIBLE int name_to_handle_at (int dirfd , const char * pathname ,
594480 struct file_handle * handle , int * mount_id ,
595481 int flags ) {
@@ -783,7 +669,15 @@ HOOK_VISIBLE int renameat2(int olddirfd, const char *oldpath, int newdirfd,
783669 errno = EACCES ;
784670 return -1 ;
785671 }
786- HOOK_GUARD (real_renameat2 , -1 );
672+ /* No renameat2 on musl: flags==0 is plain renameat(); a non-zero flag is
673+ genuinely unsupported, so ENOSYS is then the correct answer. */
674+ if (real_renameat2 == NULL ) {
675+ if (flags == 0 && real_renameat != NULL ) {
676+ return real_renameat (olddirfd , oldpath , newdirfd , newpath );
677+ }
678+ errno = ENOSYS ;
679+ return -1 ;
680+ }
787681 return real_renameat2 (olddirfd , oldpath , newdirfd , newpath , flags );
788682}
789683
0 commit comments