@@ -206,15 +206,70 @@ static void s_perror(const char *s) {
206206 if (!QUIET ) perror (s );
207207}
208208
209- // Safe .so (must be root:root, regular file, and !group/other-writable)
209+ /* Allowed roots */
210+ static const char * const TRUSTED_LIB_ROOTS [] = {
211+ "/usr/lib" ,
212+ "/lib" ,
213+ "/usr/lib64" ,
214+ "/lib64" ,
215+ NULL
216+ };
217+
218+ static int has_trusted_root (const char * real ) {
219+ for (const char * const * p = TRUSTED_LIB_ROOTS ; * p ; ++ p ) {
220+ size_t n = strlen (* p );
221+ /* must be prefix and either exactly equal or followed by '/' */
222+ if (strncmp (real , * p , n ) == 0 && (real [n ] == '\0' || real [n ] == '/' ))
223+ return 1 ;
224+ }
225+ return 0 ;
226+ }
227+
228+ /* Check that the path (already absolute) contains a component exactly "npp" */
229+ static int path_has_component_npp (const char * abs ) {
230+ /* Walk components between '/' ... '/' boundaries */
231+ const char * p = abs ;
232+ while (* p ) {
233+ /* skip repeated '/' */
234+ while (* p == '/' ) p ++ ;
235+ if (!* p ) break ;
236+ const char * start = p ;
237+ while (* p && * p != '/' ) p ++ ;
238+ size_t len = (size_t )(p - start );
239+ if (len == 3 && start [0 ] == 'n' && start [1 ] == 'p' && start [2 ] == 'p' )
240+ return 1 ;
241+ }
242+ return 0 ;
243+ }
244+
210245static int is_secure_so (const char * path ) {
211- int fd = open (path , O_RDONLY |O_CLOEXEC |O_NOFOLLOW );
212- if (fd < 0 ) return 0 ;
246+ if (!path || !* path ) return 0 ;
247+
248+ /* Resolve to a canonical absolute path (resolves all symlinks) */
249+ char real [PATH_MAX ];
250+ if (!realpath (path , real )) return 0 ;
251+
252+ /* 1) Must be under one of the trusted roots */
253+ if (!has_trusted_root (real )) return 0 ;
254+
255+ /* 2) Must include a path component exactly named "npp" somewhere below the root */
256+ if (!path_has_component_npp (real )) return 0 ;
257+
258+ /* 3) Reject final symlink and TOCTOU: open final target with O_NOFOLLOW */
259+ int fd = open (real , O_RDONLY | O_CLOEXEC | O_NOFOLLOW );
260+ if (fd < 0 ) {
261+ /* If ELOOP, final component is a symlink -> reject */
262+ return 0 ;
263+ }
264+
265+ /* 4) Ownership/permissions: root:root, regular file, not group/other writable */
213266 struct stat st ;
214267 int ok = (fstat (fd , & st ) == 0 ) &&
215268 S_ISREG (st .st_mode ) &&
216269 st .st_uid == 0 &&
270+ st .st_gid == 0 &&
217271 ((st .st_mode & 022 ) == 0 );
272+
218273 close (fd );
219274 return ok ;
220275}
0 commit comments