@@ -136,6 +136,10 @@ struct mount_attr {
136
136
#define MOUNT_ATTR_IDMAP 0x00100000
137
137
#endif
138
138
139
+ #ifndef MOUNT_ATTR_NOSYMFOLLOW
140
+ #define MOUNT_ATTR_NOSYMFOLLOW 0x00200000
141
+ #endif
142
+
139
143
static inline int sys_mount_setattr (int dfd , const char * path , unsigned int flags ,
140
144
struct mount_attr * attr , size_t size )
141
145
{
@@ -235,6 +239,10 @@ static int prepare_unpriv_mountns(void)
235
239
return 0 ;
236
240
}
237
241
242
+ #ifndef ST_NOSYMFOLLOW
243
+ #define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */
244
+ #endif
245
+
238
246
static int read_mnt_flags (const char * path )
239
247
{
240
248
int ret ;
@@ -245,9 +253,9 @@ static int read_mnt_flags(const char *path)
245
253
if (ret != 0 )
246
254
return - EINVAL ;
247
255
248
- if (stat .f_flag &
249
- ~( ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC | ST_NOATIME |
250
- ST_NODIRATIME | ST_RELATIME | ST_SYNCHRONOUS | ST_MANDLOCK ))
256
+ if (stat .f_flag & ~( ST_RDONLY | ST_NOSUID | ST_NODEV | ST_NOEXEC |
257
+ ST_NOATIME | ST_NODIRATIME | ST_RELATIME |
258
+ ST_SYNCHRONOUS | ST_MANDLOCK | ST_NOSYMFOLLOW ))
251
259
return - EINVAL ;
252
260
253
261
mnt_flags = 0 ;
@@ -269,6 +277,8 @@ static int read_mnt_flags(const char *path)
269
277
mnt_flags |= MS_SYNCHRONOUS ;
270
278
if (stat .f_flag & ST_MANDLOCK )
271
279
mnt_flags |= ST_MANDLOCK ;
280
+ if (stat .f_flag & ST_NOSYMFOLLOW )
281
+ mnt_flags |= ST_NOSYMFOLLOW ;
272
282
273
283
return mnt_flags ;
274
284
}
@@ -368,8 +378,13 @@ static bool mount_setattr_supported(void)
368
378
FIXTURE (mount_setattr ) {
369
379
};
370
380
381
+ #define NOSYMFOLLOW_TARGET "/mnt/A/AA/data"
382
+ #define NOSYMFOLLOW_SYMLINK "/mnt/A/AA/symlink"
383
+
371
384
FIXTURE_SETUP (mount_setattr )
372
385
{
386
+ int fd = - EBADF ;
387
+
373
388
if (!mount_setattr_supported ())
374
389
SKIP (return , "mount_setattr syscall not supported" );
375
390
@@ -412,6 +427,11 @@ FIXTURE_SETUP(mount_setattr)
412
427
413
428
ASSERT_EQ (mount ("testing" , "/tmp/B/BB" , "devpts" ,
414
429
MS_RELATIME | MS_NOEXEC | MS_RDONLY , 0 ), 0 );
430
+
431
+ fd = creat (NOSYMFOLLOW_TARGET , O_RDWR | O_CLOEXEC );
432
+ ASSERT_GT (fd , 0 );
433
+ ASSERT_EQ (symlink (NOSYMFOLLOW_TARGET , NOSYMFOLLOW_SYMLINK ), 0 );
434
+ ASSERT_EQ (close (fd ), 0 );
415
435
}
416
436
417
437
FIXTURE_TEARDOWN (mount_setattr )
@@ -1421,4 +1441,66 @@ TEST_F(mount_setattr_idmapped, idmap_mount_tree_invalid)
1421
1441
ASSERT_EQ (expected_uid_gid (open_tree_fd , "B/BB/b" , 0 , 0 , 0 ), 0 );
1422
1442
}
1423
1443
1444
+ TEST_F (mount_setattr , mount_attr_nosymfollow )
1445
+ {
1446
+ int fd ;
1447
+ unsigned int old_flags = 0 , new_flags = 0 , expected_flags = 0 ;
1448
+ struct mount_attr attr = {
1449
+ .attr_set = MOUNT_ATTR_NOSYMFOLLOW ,
1450
+ };
1451
+
1452
+ if (!mount_setattr_supported ())
1453
+ SKIP (return , "mount_setattr syscall not supported" );
1454
+
1455
+ fd = open (NOSYMFOLLOW_SYMLINK , O_RDWR | O_CLOEXEC );
1456
+ ASSERT_GT (fd , 0 );
1457
+ ASSERT_EQ (close (fd ), 0 );
1458
+
1459
+ old_flags = read_mnt_flags ("/mnt/A" );
1460
+ ASSERT_GT (old_flags , 0 );
1461
+
1462
+ ASSERT_EQ (sys_mount_setattr (-1 , "/mnt/A" , AT_RECURSIVE , & attr , sizeof (attr )), 0 );
1463
+
1464
+ expected_flags = old_flags ;
1465
+ expected_flags |= ST_NOSYMFOLLOW ;
1466
+
1467
+ new_flags = read_mnt_flags ("/mnt/A" );
1468
+ ASSERT_EQ (new_flags , expected_flags );
1469
+
1470
+ new_flags = read_mnt_flags ("/mnt/A/AA" );
1471
+ ASSERT_EQ (new_flags , expected_flags );
1472
+
1473
+ new_flags = read_mnt_flags ("/mnt/A/AA/B" );
1474
+ ASSERT_EQ (new_flags , expected_flags );
1475
+
1476
+ new_flags = read_mnt_flags ("/mnt/A/AA/B/BB" );
1477
+ ASSERT_EQ (new_flags , expected_flags );
1478
+
1479
+ fd = open (NOSYMFOLLOW_SYMLINK , O_RDWR | O_CLOEXEC );
1480
+ ASSERT_LT (fd , 0 );
1481
+ ASSERT_EQ (errno , ELOOP );
1482
+
1483
+ attr .attr_set &= ~MOUNT_ATTR_NOSYMFOLLOW ;
1484
+ attr .attr_clr |= MOUNT_ATTR_NOSYMFOLLOW ;
1485
+
1486
+ ASSERT_EQ (sys_mount_setattr (-1 , "/mnt/A" , AT_RECURSIVE , & attr , sizeof (attr )), 0 );
1487
+
1488
+ expected_flags &= ~ST_NOSYMFOLLOW ;
1489
+ new_flags = read_mnt_flags ("/mnt/A" );
1490
+ ASSERT_EQ (new_flags , expected_flags );
1491
+
1492
+ new_flags = read_mnt_flags ("/mnt/A/AA" );
1493
+ ASSERT_EQ (new_flags , expected_flags );
1494
+
1495
+ new_flags = read_mnt_flags ("/mnt/A/AA/B" );
1496
+ ASSERT_EQ (new_flags , expected_flags );
1497
+
1498
+ new_flags = read_mnt_flags ("/mnt/A/AA/B/BB" );
1499
+ ASSERT_EQ (new_flags , expected_flags );
1500
+
1501
+ fd = open (NOSYMFOLLOW_SYMLINK , O_RDWR | O_CLOEXEC );
1502
+ ASSERT_GT (fd , 0 );
1503
+ ASSERT_EQ (close (fd ), 0 );
1504
+ }
1505
+
1424
1506
TEST_HARNESS_MAIN
0 commit comments