16
16
17
17
struct ovl_lookup_data {
18
18
struct super_block * sb ;
19
+ struct dentry * dentry ;
19
20
const struct ovl_layer * layer ;
20
21
struct qstr name ;
21
22
bool is_dir ;
@@ -24,6 +25,7 @@ struct ovl_lookup_data {
24
25
bool stop ;
25
26
bool last ;
26
27
char * redirect ;
28
+ char * upperredirect ;
27
29
int metacopy ;
28
30
/* Referring to last redirect xattr */
29
31
bool absolute_redirect ;
@@ -1024,6 +1026,31 @@ int ovl_verify_lowerdata(struct dentry *dentry)
1024
1026
return ovl_maybe_validate_verity (dentry );
1025
1027
}
1026
1028
1029
+ /*
1030
+ * Following redirects/metacopy can have security consequences: it's like a
1031
+ * symlink into the lower layer without the permission checks.
1032
+ *
1033
+ * This is only a problem if the upper layer is untrusted (e.g comes from an USB
1034
+ * drive). This can allow a non-readable file or directory to become readable.
1035
+ *
1036
+ * Only following redirects when redirects are enabled disables this attack
1037
+ * vector when not necessary.
1038
+ */
1039
+ static bool ovl_check_follow_redirect (struct ovl_lookup_data * d )
1040
+ {
1041
+ struct ovl_fs * ofs = OVL_FS (d -> sb );
1042
+
1043
+ if (d -> metacopy && !ofs -> config .metacopy ) {
1044
+ pr_warn_ratelimited ("refusing to follow metacopy origin for (%pd2)\n" , d -> dentry );
1045
+ return false;
1046
+ }
1047
+ if ((d -> redirect || d -> upperredirect ) && !ovl_redirect_follow (ofs )) {
1048
+ pr_warn_ratelimited ("refusing to follow redirect for (%pd2)\n" , d -> dentry );
1049
+ return false;
1050
+ }
1051
+ return true;
1052
+ }
1053
+
1027
1054
struct dentry * ovl_lookup (struct inode * dir , struct dentry * dentry ,
1028
1055
unsigned int flags )
1029
1056
{
@@ -1039,20 +1066,22 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
1039
1066
unsigned int ctr = 0 ;
1040
1067
struct inode * inode = NULL ;
1041
1068
bool upperopaque = false;
1042
- char * upperredirect = NULL ;
1069
+ bool check_redirect = ( ovl_redirect_follow ( ofs ) || ofs -> numdatalayer ) ;
1043
1070
struct dentry * this ;
1044
1071
unsigned int i ;
1045
1072
int err ;
1046
1073
bool uppermetacopy = false;
1047
1074
int metacopy_size = 0 ;
1048
1075
struct ovl_lookup_data d = {
1049
1076
.sb = dentry -> d_sb ,
1077
+ .dentry = dentry ,
1050
1078
.name = dentry -> d_name ,
1051
1079
.is_dir = false,
1052
1080
.opaque = false,
1053
1081
.stop = false,
1054
- .last = ovl_redirect_follow ( ofs ) ? false : !ovl_numlower (poe ),
1082
+ .last = check_redirect ? false : !ovl_numlower (poe ),
1055
1083
.redirect = NULL ,
1084
+ .upperredirect = NULL ,
1056
1085
.metacopy = 0 ,
1057
1086
};
1058
1087
@@ -1094,8 +1123,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
1094
1123
1095
1124
if (d .redirect ) {
1096
1125
err = - ENOMEM ;
1097
- upperredirect = kstrdup (d .redirect , GFP_KERNEL );
1098
- if (!upperredirect )
1126
+ d . upperredirect = kstrdup (d .redirect , GFP_KERNEL );
1127
+ if (!d . upperredirect )
1099
1128
goto out_put_upper ;
1100
1129
if (d .redirect [0 ] == '/' )
1101
1130
poe = roe ;
@@ -1113,7 +1142,12 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
1113
1142
for (i = 0 ; !d .stop && i < ovl_numlower (poe ); i ++ ) {
1114
1143
struct ovl_path lower = ovl_lowerstack (poe )[i ];
1115
1144
1116
- if (!ovl_redirect_follow (ofs ))
1145
+ if (!ovl_check_follow_redirect (& d )) {
1146
+ err = - EPERM ;
1147
+ goto out_put ;
1148
+ }
1149
+
1150
+ if (!check_redirect )
1117
1151
d .last = i == ovl_numlower (poe ) - 1 ;
1118
1152
else if (d .is_dir || !ofs -> numdatalayer )
1119
1153
d .last = lower .layer -> idx == ovl_numlower (roe );
@@ -1126,13 +1160,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
1126
1160
if (!this )
1127
1161
continue ;
1128
1162
1129
- if ((uppermetacopy || d .metacopy ) && !ofs -> config .metacopy ) {
1130
- dput (this );
1131
- err = - EPERM ;
1132
- pr_warn_ratelimited ("refusing to follow metacopy origin for (%pd2)\n" , dentry );
1133
- goto out_put ;
1134
- }
1135
-
1136
1163
/*
1137
1164
* If no origin fh is stored in upper of a merge dir, store fh
1138
1165
* of lower dir and set upper parent "impure".
@@ -1185,23 +1212,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
1185
1212
ctr ++ ;
1186
1213
}
1187
1214
1188
- /*
1189
- * Following redirects can have security consequences: it's like
1190
- * a symlink into the lower layer without the permission checks.
1191
- * This is only a problem if the upper layer is untrusted (e.g
1192
- * comes from an USB drive). This can allow a non-readable file
1193
- * or directory to become readable.
1194
- *
1195
- * Only following redirects when redirects are enabled disables
1196
- * this attack vector when not necessary.
1197
- */
1198
- err = - EPERM ;
1199
- if (d .redirect && !ovl_redirect_follow (ofs )) {
1200
- pr_warn_ratelimited ("refusing to follow redirect for (%pd2)\n" ,
1201
- dentry );
1202
- goto out_put ;
1203
- }
1204
-
1205
1215
if (d .stop )
1206
1216
break ;
1207
1217
@@ -1212,10 +1222,16 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
1212
1222
}
1213
1223
}
1214
1224
1215
- /* Defer lookup of lowerdata in data-only layers to first access */
1225
+ /*
1226
+ * Defer lookup of lowerdata in data-only layers to first access.
1227
+ * Don't require redirect=follow and metacopy=on in this case.
1228
+ */
1216
1229
if (d .metacopy && ctr && ofs -> numdatalayer && d .absolute_redirect ) {
1217
1230
d .metacopy = 0 ;
1218
1231
ctr ++ ;
1232
+ } else if (!ovl_check_follow_redirect (& d )) {
1233
+ err = - EPERM ;
1234
+ goto out_put ;
1219
1235
}
1220
1236
1221
1237
/*
@@ -1298,28 +1314,34 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
1298
1314
1299
1315
/*
1300
1316
* It's safe to assign upperredirect here: the previous
1301
- * assignment of happens only if upperdentry is non-NULL, and
1317
+ * assignment happens only if upperdentry is non-NULL, and
1302
1318
* this one only if upperdentry is NULL.
1303
1319
*/
1304
- upperredirect = ovl_get_redirect_xattr (ofs , & upperpath , 0 );
1305
- if (IS_ERR (upperredirect )) {
1306
- err = PTR_ERR (upperredirect );
1307
- upperredirect = NULL ;
1320
+ d . upperredirect = ovl_get_redirect_xattr (ofs , & upperpath , 0 );
1321
+ if (IS_ERR (d . upperredirect )) {
1322
+ err = PTR_ERR (d . upperredirect );
1323
+ d . upperredirect = NULL ;
1308
1324
goto out_free_oe ;
1309
1325
}
1326
+
1310
1327
err = ovl_check_metacopy_xattr (ofs , & upperpath , NULL );
1311
1328
if (err < 0 )
1312
1329
goto out_free_oe ;
1313
- uppermetacopy = err ;
1330
+ d . metacopy = uppermetacopy = err ;
1314
1331
metacopy_size = err ;
1332
+
1333
+ if (!ovl_check_follow_redirect (& d )) {
1334
+ err = - EPERM ;
1335
+ goto out_free_oe ;
1336
+ }
1315
1337
}
1316
1338
1317
1339
if (upperdentry || ctr ) {
1318
1340
struct ovl_inode_params oip = {
1319
1341
.upperdentry = upperdentry ,
1320
1342
.oe = oe ,
1321
1343
.index = index ,
1322
- .redirect = upperredirect ,
1344
+ .redirect = d . upperredirect ,
1323
1345
};
1324
1346
1325
1347
/* Store lowerdata redirect for lazy lookup */
@@ -1361,7 +1383,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
1361
1383
kfree (origin_path );
1362
1384
}
1363
1385
dput (upperdentry );
1364
- kfree (upperredirect );
1386
+ kfree (d . upperredirect );
1365
1387
out :
1366
1388
kfree (d .redirect );
1367
1389
ovl_revert_creds (old_cred );
0 commit comments