@@ -64,6 +64,7 @@ struct nfsd4_client_tracking_ops {
64
64
};
65
65
66
66
static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops ;
67
+ static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2 ;
67
68
68
69
/* Globals */
69
70
static char user_recovery_dirname [PATH_MAX ] = "/var/lib/nfs/v4recovery" ;
@@ -177,6 +178,7 @@ __nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
177
178
const char * dname , int len , struct nfsd_net * nn )
178
179
{
179
180
struct xdr_netobj name ;
181
+ struct xdr_netobj princhash = { .len = 0 , .data = NULL };
180
182
struct nfs4_client_reclaim * crp ;
181
183
182
184
name .data = kmemdup (dname , len , GFP_KERNEL );
@@ -186,7 +188,7 @@ __nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
186
188
return ;
187
189
}
188
190
name .len = len ;
189
- crp = nfs4_client_to_reclaim (name , nn );
191
+ crp = nfs4_client_to_reclaim (name , princhash , nn );
190
192
if (!crp ) {
191
193
kfree (name .data );
192
194
return ;
@@ -486,6 +488,7 @@ static int
486
488
load_recdir (struct dentry * parent , struct dentry * child , struct nfsd_net * nn )
487
489
{
488
490
struct xdr_netobj name ;
491
+ struct xdr_netobj princhash = { .len = 0 , .data = NULL };
489
492
490
493
if (child -> d_name .len != HEXDIR_LEN - 1 ) {
491
494
printk ("%s: illegal name %pd in recovery directory\n" ,
@@ -500,7 +503,7 @@ load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
500
503
goto out ;
501
504
}
502
505
name .len = HEXDIR_LEN ;
503
- if (!nfs4_client_to_reclaim (name , nn ))
506
+ if (!nfs4_client_to_reclaim (name , princhash , nn ))
504
507
kfree (name .data );
505
508
out :
506
509
return 0 ;
@@ -737,6 +740,7 @@ struct cld_net {
737
740
struct list_head cn_list ;
738
741
unsigned int cn_xid ;
739
742
bool cn_has_legacy ;
743
+ struct crypto_shash * cn_tfm ;
740
744
};
741
745
742
746
struct cld_upcall {
@@ -746,6 +750,7 @@ struct cld_upcall {
746
750
union {
747
751
struct cld_msg_hdr cu_hdr ;
748
752
struct cld_msg cu_msg ;
753
+ struct cld_msg_v2 cu_msg_v2 ;
749
754
} cu_u ;
750
755
};
751
756
@@ -792,11 +797,11 @@ cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg)
792
797
}
793
798
794
799
static ssize_t
795
- __cld_pipe_inprogress_downcall (const struct cld_msg __user * cmsg ,
800
+ __cld_pipe_inprogress_downcall (const struct cld_msg_v2 __user * cmsg ,
796
801
struct nfsd_net * nn )
797
802
{
798
- uint8_t cmd ;
799
- struct xdr_netobj name ;
803
+ uint8_t cmd , princhashlen ;
804
+ struct xdr_netobj name , princhash = { . len = 0 , . data = NULL } ;
800
805
uint16_t namelen ;
801
806
struct cld_net * cn = nn -> cld_net ;
802
807
@@ -805,19 +810,45 @@ __cld_pipe_inprogress_downcall(const struct cld_msg __user *cmsg,
805
810
return - EFAULT ;
806
811
}
807
812
if (cmd == Cld_GraceStart ) {
808
- if (get_user (namelen , & cmsg -> cm_u .cm_name .cn_len ))
809
- return - EFAULT ;
810
- name .data = memdup_user (& cmsg -> cm_u .cm_name .cn_id , namelen );
811
- if (IS_ERR_OR_NULL (name .data ))
812
- return - EFAULT ;
813
- name .len = namelen ;
813
+ if (nn -> client_tracking_ops -> version >= 2 ) {
814
+ const struct cld_clntinfo __user * ci ;
815
+
816
+ ci = & cmsg -> cm_u .cm_clntinfo ;
817
+ if (get_user (namelen , & ci -> cc_name .cn_len ))
818
+ return - EFAULT ;
819
+ name .data = memdup_user (& ci -> cc_name .cn_id , namelen );
820
+ if (IS_ERR_OR_NULL (name .data ))
821
+ return - EFAULT ;
822
+ name .len = namelen ;
823
+ get_user (princhashlen , & ci -> cc_princhash .cp_len );
824
+ if (princhashlen > 0 ) {
825
+ princhash .data = memdup_user (
826
+ & ci -> cc_princhash .cp_data ,
827
+ princhashlen );
828
+ if (IS_ERR_OR_NULL (princhash .data ))
829
+ return - EFAULT ;
830
+ princhash .len = princhashlen ;
831
+ } else
832
+ princhash .len = 0 ;
833
+ } else {
834
+ const struct cld_name __user * cnm ;
835
+
836
+ cnm = & cmsg -> cm_u .cm_name ;
837
+ if (get_user (namelen , & cnm -> cn_len ))
838
+ return - EFAULT ;
839
+ name .data = memdup_user (& cnm -> cn_id , namelen );
840
+ if (IS_ERR_OR_NULL (name .data ))
841
+ return - EFAULT ;
842
+ name .len = namelen ;
843
+ }
814
844
if (name .len > 5 && memcmp (name .data , "hash:" , 5 ) == 0 ) {
815
845
name .len = name .len - 5 ;
816
846
memmove (name .data , name .data + 5 , name .len );
817
847
cn -> cn_has_legacy = true;
818
848
}
819
- if (!nfs4_client_to_reclaim (name , nn )) {
849
+ if (!nfs4_client_to_reclaim (name , princhash , nn )) {
820
850
kfree (name .data );
851
+ kfree (princhash .data );
821
852
return - EFAULT ;
822
853
}
823
854
return nn -> client_tracking_ops -> msglen ;
@@ -830,7 +861,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
830
861
{
831
862
struct cld_upcall * tmp , * cup ;
832
863
struct cld_msg_hdr __user * hdr = (struct cld_msg_hdr __user * )src ;
833
- struct cld_msg __user * cmsg = (struct cld_msg __user * )src ;
864
+ struct cld_msg_v2 __user * cmsg = (struct cld_msg_v2 __user * )src ;
834
865
uint32_t xid ;
835
866
struct nfsd_net * nn = net_generic (file_inode (filp )-> i_sb -> s_fs_info ,
836
867
nfsd_net_id );
@@ -881,7 +912,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
881
912
if (status == - EINPROGRESS )
882
913
return __cld_pipe_inprogress_downcall (cmsg , nn );
883
914
884
- if (copy_from_user (& cup -> cu_u .cu_msg , src , mlen ) != 0 )
915
+ if (copy_from_user (& cup -> cu_u .cu_msg_v2 , src , mlen ) != 0 )
885
916
return - EFAULT ;
886
917
887
918
complete (& cup -> cu_done );
@@ -1019,6 +1050,8 @@ nfsd4_remove_cld_pipe(struct net *net)
1019
1050
1020
1051
nfsd4_cld_unregister_net (net , cn -> cn_pipe );
1021
1052
rpc_destroy_pipe_data (cn -> cn_pipe );
1053
+ if (cn -> cn_tfm )
1054
+ crypto_free_shash (cn -> cn_tfm );
1022
1055
kfree (nn -> cld_net );
1023
1056
nn -> cld_net = NULL ;
1024
1057
}
@@ -1103,6 +1136,75 @@ nfsd4_cld_create(struct nfs4_client *clp)
1103
1136
"record on stable storage: %d\n" , ret );
1104
1137
}
1105
1138
1139
+ /* Ask daemon to create a new record */
1140
+ static void
1141
+ nfsd4_cld_create_v2 (struct nfs4_client * clp )
1142
+ {
1143
+ int ret ;
1144
+ struct cld_upcall * cup ;
1145
+ struct nfsd_net * nn = net_generic (clp -> net , nfsd_net_id );
1146
+ struct cld_net * cn = nn -> cld_net ;
1147
+ struct cld_msg_v2 * cmsg ;
1148
+ struct crypto_shash * tfm = cn -> cn_tfm ;
1149
+ struct xdr_netobj cksum ;
1150
+ char * principal = NULL ;
1151
+ SHASH_DESC_ON_STACK (desc , tfm );
1152
+
1153
+ /* Don't upcall if it's already stored */
1154
+ if (test_bit (NFSD4_CLIENT_STABLE , & clp -> cl_flags ))
1155
+ return ;
1156
+
1157
+ cup = alloc_cld_upcall (nn );
1158
+ if (!cup ) {
1159
+ ret = - ENOMEM ;
1160
+ goto out_err ;
1161
+ }
1162
+
1163
+ cmsg = & cup -> cu_u .cu_msg_v2 ;
1164
+ cmsg -> cm_cmd = Cld_Create ;
1165
+ cmsg -> cm_u .cm_clntinfo .cc_name .cn_len = clp -> cl_name .len ;
1166
+ memcpy (cmsg -> cm_u .cm_clntinfo .cc_name .cn_id , clp -> cl_name .data ,
1167
+ clp -> cl_name .len );
1168
+ if (clp -> cl_cred .cr_raw_principal )
1169
+ principal = clp -> cl_cred .cr_raw_principal ;
1170
+ else if (clp -> cl_cred .cr_principal )
1171
+ principal = clp -> cl_cred .cr_principal ;
1172
+ if (principal ) {
1173
+ desc -> tfm = tfm ;
1174
+ cksum .len = crypto_shash_digestsize (tfm );
1175
+ cksum .data = kmalloc (cksum .len , GFP_KERNEL );
1176
+ if (cksum .data == NULL ) {
1177
+ ret = - ENOMEM ;
1178
+ goto out ;
1179
+ }
1180
+ ret = crypto_shash_digest (desc , principal , strlen (principal ),
1181
+ cksum .data );
1182
+ shash_desc_zero (desc );
1183
+ if (ret ) {
1184
+ kfree (cksum .data );
1185
+ goto out ;
1186
+ }
1187
+ cmsg -> cm_u .cm_clntinfo .cc_princhash .cp_len = cksum .len ;
1188
+ memcpy (cmsg -> cm_u .cm_clntinfo .cc_princhash .cp_data ,
1189
+ cksum .data , cksum .len );
1190
+ kfree (cksum .data );
1191
+ } else
1192
+ cmsg -> cm_u .cm_clntinfo .cc_princhash .cp_len = 0 ;
1193
+
1194
+ ret = cld_pipe_upcall (cn -> cn_pipe , cmsg );
1195
+ if (!ret ) {
1196
+ ret = cmsg -> cm_status ;
1197
+ set_bit (NFSD4_CLIENT_STABLE , & clp -> cl_flags );
1198
+ }
1199
+
1200
+ out :
1201
+ free_cld_upcall (cup );
1202
+ out_err :
1203
+ if (ret )
1204
+ pr_err ("NFSD: Unable to create client record on stable storage: %d\n" ,
1205
+ ret );
1206
+ }
1207
+
1106
1208
/* Ask daemon to create a new record */
1107
1209
static void
1108
1210
nfsd4_cld_remove (struct nfs4_client * clp )
@@ -1229,6 +1331,79 @@ nfsd4_cld_check(struct nfs4_client *clp)
1229
1331
return 0 ;
1230
1332
}
1231
1333
1334
+ static int
1335
+ nfsd4_cld_check_v2 (struct nfs4_client * clp )
1336
+ {
1337
+ struct nfs4_client_reclaim * crp ;
1338
+ struct nfsd_net * nn = net_generic (clp -> net , nfsd_net_id );
1339
+ struct cld_net * cn = nn -> cld_net ;
1340
+ int status ;
1341
+ char dname [HEXDIR_LEN ];
1342
+ struct xdr_netobj name ;
1343
+ struct crypto_shash * tfm = cn -> cn_tfm ;
1344
+ struct xdr_netobj cksum ;
1345
+ char * principal = NULL ;
1346
+ SHASH_DESC_ON_STACK (desc , tfm );
1347
+
1348
+ /* did we already find that this client is stable? */
1349
+ if (test_bit (NFSD4_CLIENT_STABLE , & clp -> cl_flags ))
1350
+ return 0 ;
1351
+
1352
+ /* look for it in the reclaim hashtable otherwise */
1353
+ crp = nfsd4_find_reclaim_client (clp -> cl_name , nn );
1354
+ if (crp )
1355
+ goto found ;
1356
+
1357
+ if (cn -> cn_has_legacy ) {
1358
+ status = nfs4_make_rec_clidname (dname , & clp -> cl_name );
1359
+ if (status )
1360
+ return - ENOENT ;
1361
+
1362
+ name .data = kmemdup (dname , HEXDIR_LEN , GFP_KERNEL );
1363
+ if (!name .data ) {
1364
+ dprintk ("%s: failed to allocate memory for name.data\n" ,
1365
+ __func__ );
1366
+ return - ENOENT ;
1367
+ }
1368
+ name .len = HEXDIR_LEN ;
1369
+ crp = nfsd4_find_reclaim_client (name , nn );
1370
+ kfree (name .data );
1371
+ if (crp )
1372
+ goto found ;
1373
+
1374
+ }
1375
+ return - ENOENT ;
1376
+ found :
1377
+ if (crp -> cr_princhash .len ) {
1378
+ if (clp -> cl_cred .cr_raw_principal )
1379
+ principal = clp -> cl_cred .cr_raw_principal ;
1380
+ else if (clp -> cl_cred .cr_principal )
1381
+ principal = clp -> cl_cred .cr_principal ;
1382
+ if (principal == NULL )
1383
+ return - ENOENT ;
1384
+ desc -> tfm = tfm ;
1385
+ cksum .len = crypto_shash_digestsize (tfm );
1386
+ cksum .data = kmalloc (cksum .len , GFP_KERNEL );
1387
+ if (cksum .data == NULL )
1388
+ return - ENOENT ;
1389
+ status = crypto_shash_digest (desc , principal , strlen (principal ),
1390
+ cksum .data );
1391
+ shash_desc_zero (desc );
1392
+ if (status ) {
1393
+ kfree (cksum .data );
1394
+ return - ENOENT ;
1395
+ }
1396
+ if (memcmp (crp -> cr_princhash .data , cksum .data ,
1397
+ crp -> cr_princhash .len )) {
1398
+ kfree (cksum .data );
1399
+ return - ENOENT ;
1400
+ }
1401
+ kfree (cksum .data );
1402
+ }
1403
+ crp -> cr_clp = clp ;
1404
+ return 0 ;
1405
+ }
1406
+
1232
1407
static int
1233
1408
nfsd4_cld_grace_start (struct nfsd_net * nn )
1234
1409
{
@@ -1380,6 +1555,9 @@ nfsd4_cld_get_version(struct nfsd_net *nn)
1380
1555
case 1 :
1381
1556
nn -> client_tracking_ops = & nfsd4_cld_tracking_ops ;
1382
1557
break ;
1558
+ case 2 :
1559
+ nn -> client_tracking_ops = & nfsd4_cld_tracking_ops_v2 ;
1560
+ break ;
1383
1561
default :
1384
1562
break ;
1385
1563
}
@@ -1408,6 +1586,11 @@ nfsd4_cld_tracking_init(struct net *net)
1408
1586
status = __nfsd4_init_cld_pipe (net );
1409
1587
if (status )
1410
1588
goto err_shutdown ;
1589
+ nn -> cld_net -> cn_tfm = crypto_alloc_shash ("sha256" , 0 , 0 );
1590
+ if (IS_ERR (nn -> cld_net -> cn_tfm )) {
1591
+ status = PTR_ERR (nn -> cld_net -> cn_tfm );
1592
+ goto err_remove ;
1593
+ }
1411
1594
1412
1595
/*
1413
1596
* rpc pipe upcalls take 30 seconds to time out, so we don't want to
@@ -1480,6 +1663,18 @@ static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
1480
1663
.msglen = sizeof (struct cld_msg ),
1481
1664
};
1482
1665
1666
+ /* v2 create/check ops include the principal, if available */
1667
+ static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2 = {
1668
+ .init = nfsd4_cld_tracking_init ,
1669
+ .exit = nfsd4_cld_tracking_exit ,
1670
+ .create = nfsd4_cld_create_v2 ,
1671
+ .remove = nfsd4_cld_remove ,
1672
+ .check = nfsd4_cld_check_v2 ,
1673
+ .grace_done = nfsd4_cld_grace_done ,
1674
+ .version = 2 ,
1675
+ .msglen = sizeof (struct cld_msg_v2 ),
1676
+ };
1677
+
1483
1678
/* upcall via usermodehelper */
1484
1679
static char cltrack_prog [PATH_MAX ] = "/sbin/nfsdcltrack" ;
1485
1680
module_param_string (cltrack_prog , cltrack_prog , sizeof (cltrack_prog ),
0 commit comments