fork(1) download
  1. struct group_info init_groups = { .usage = ATOMIC_INIT(2) };
  2.  
  3. struct group_info *groups_alloc(int gidsetsize){
  4. struct group_info *group_info;
  5. int nblocks;
  6. int i;
  7.  
  8.  
  9. nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK;
  10. /* Make sure we always allocate at least one indirect block pointer */
  11. nblocks = nblocks ? : 1;
  12. group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
  13. if (!group_info)
  14. return NULL;
  15.  
  16. group_info->ngroups = gidsetsize;
  17. group_info->nblocks = nblocks;
  18. atomic_set(&group_info->usage, 1);
  19.  
  20. if (gidsetsize <= NGROUPS_SMALL)
  21. group_info->blocks[0] = group_info->small_block;
  22. else {
  23. for (i = 0; i < nblocks; i++) {
  24. gid_t *b;
  25. b = (void *)__get_free_page(GFP_USER);
  26. if (!b)
  27. goto out_undo_partial_alloc;
  28. group_info->blocks[i] = b;
  29. }
  30. }
  31. return group_info;
  32.  
  33.  
  34. out_undo_partial_alloc:
  35.  
  36. while (--i >= 0) {
  37.  
  38. free_page((unsigned long)group_info->blocks[i]);
  39.  
  40. }
  41.  
  42. kfree(group_info);
  43.  
  44. return NULL;
  45.  
  46. }
  47.  
  48.  
  49.  
  50. EXPORT_SYMBOL(groups_alloc);
  51.  
  52.  
  53.  
  54. void groups_free(struct group_info *group_info)
  55.  
  56. {
  57.  
  58. if (group_info->blocks[0] != group_info->small_block) {
  59.  
  60. int i;
  61.  
  62. for (i = 0; i < group_info->nblocks; i++)
  63.  
  64. free_page((unsigned long)group_info->blocks[i]);
  65.  
  66. }
  67.  
  68. kfree(group_info);
  69.  
  70. }
  71.  
  72.  
  73.  
  74. EXPORT_SYMBOL(groups_free);
  75.  
  76.  
  77.  
  78. /* export the group_info to a user-space array */
  79.  
  80. static int groups_to_user(gid_t __user *grouplist,
  81.  
  82. const struct group_info *group_info)
  83.  
  84. {
  85.  
  86. int i;
  87.  
  88. unsigned int count = group_info->ngroups;
  89.  
  90.  
  91.  
  92. for (i = 0; i < group_info->nblocks; i++) {
  93.  
  94. unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
  95.  
  96. unsigned int len = cp_count * sizeof(*grouplist);
  97.  
  98.  
  99.  
  100. if (copy_to_user(grouplist, group_info->blocks[i], len))
  101.  
  102. return -EFAULT;
  103.  
  104.  
  105.  
  106. grouplist += NGROUPS_PER_BLOCK;
  107.  
  108. count -= cp_count;
  109.  
  110. }
  111.  
  112. return 0;
  113.  
  114. }
  115.  
  116.  
  117.  
  118. /* fill a group_info from a user-space array - it must be allocated already */
  119.  
  120. static int groups_from_user(struct group_info *group_info,
  121.  
  122. gid_t __user *grouplist)
  123.  
  124. {
  125.  
  126. int i;
  127.  
  128. unsigned int count = group_info->ngroups;
  129.  
  130.  
  131.  
  132. for (i = 0; i < group_info->nblocks; i++) {
  133.  
  134. unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
  135.  
  136. unsigned int len = cp_count * sizeof(*grouplist);
  137.  
  138.  
  139.  
  140. if (copy_from_user(group_info->blocks[i], grouplist, len))
  141.  
  142. return -EFAULT;
  143.  
  144.  
  145.  
  146. grouplist += NGROUPS_PER_BLOCK;
  147.  
  148. count -= cp_count;
  149.  
  150. }
  151.  
  152. return 0;
  153.  
  154. }
  155.  
  156.  
  157.  
  158. /* a simple Shell sort */
  159.  
  160. static void groups_sort(struct group_info *group_info)
  161.  
  162. {
  163.  
  164. int base, max, stride;
  165.  
  166. int gidsetsize = group_info->ngroups;
  167.  
  168.  
  169.  
  170. for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
  171.  
  172. ; /* nothing */
  173.  
  174. stride /= 3;
  175.  
  176.  
  177.  
  178. while (stride) {
  179.  
  180. max = gidsetsize - stride;
  181.  
  182. for (base = 0; base < max; base++) {
  183.  
  184. int left = base;
  185.  
  186. int right = left + stride;
  187.  
  188. gid_t tmp = GROUP_AT(group_info, right);
  189.  
  190.  
  191.  
  192. while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
  193.  
  194. GROUP_AT(group_info, right) =
  195.  
  196. GROUP_AT(group_info, left);
  197.  
  198. right = left;
  199.  
  200. left -= stride;
  201.  
  202. }
  203.  
  204. GROUP_AT(group_info, right) = tmp;
  205.  
  206. }
  207.  
  208. stride /= 3;
  209.  
  210. }
  211.  
  212. }
  213.  
  214.  
  215.  
  216. /* a simple bsearch */
  217.  
  218. int groups_search(const struct group_info *group_info, gid_t grp)
  219.  
  220. {
  221.  
  222. unsigned int left, right;
  223.  
  224.  
  225.  
  226. if (!group_info)
  227.  
  228. return 0;
  229.  
  230.  
  231.  
  232. left = 0;
  233.  
  234. right = group_info->ngroups;
  235.  
  236. while (left < right) {
  237.  
  238. unsigned int mid = left + (right - left)/2;
  239.  
  240. if (grp > GROUP_AT(group_info, mid))
  241.  
  242. left = mid + 1;
  243.  
  244. else if (grp < GROUP_AT(group_info, mid))
  245.  
  246. right = mid;
  247.  
  248. else
  249.  
  250. return 1;
  251.  
  252. }
  253.  
  254. return 0;
  255.  
  256. }
  257.  
  258.  
  259.  
  260. /**
  261.  
  262.  * set_groups - Change a group subscription in a set of credentials
  263.  
  264.  * @new: The newly prepared set of credentials to alter
  265.  
  266.  * @group_info: The group list to install
  267.  
  268.  *
  269.  
  270.  * Validate a group subscription and, if valid, insert it into a set
  271.  
  272.  * of credentials.
  273.  
  274.  */
  275.  
  276. int set_groups(struct cred *new, struct group_info *group_info)
  277.  
  278. {
  279.  
  280. put_group_info(new->group_info);
  281.  
  282. groups_sort(group_info);
  283.  
  284. get_group_info(group_info);
  285.  
  286. new->group_info = group_info;
  287.  
  288. return 0;
  289.  
  290. }
  291.  
  292.  
  293.  
  294. EXPORT_SYMBOL(set_groups);
  295.  
  296.  
  297.  
  298. /**
  299.  
  300.  * set_current_groups - Change current's group subscription
  301.  
  302.  * @group_info: The group list to impose
  303.  
  304.  *
  305.  
  306.  * Validate a group subscription and, if valid, impose it upon current's task
  307.  
  308.  * security record.
  309.  
  310.  */
  311.  
  312. int set_current_groups(struct group_info *group_info)
  313.  
  314. {
  315.  
  316. struct cred *new;
  317.  
  318. int ret;
  319.  
  320.  
  321.  
  322. new = prepare_creds();
  323.  
  324. if (!new)
  325.  
  326. return -ENOMEM;
  327.  
  328.  
  329.  
  330. ret = set_groups(new, group_info);
  331.  
  332. if (ret < 0) {
  333.  
  334. abort_creds(new);
  335.  
  336. return ret;
  337.  
  338. }
  339.  
  340.  
  341.  
  342. return commit_creds(new);
  343.  
  344. }
  345.  
  346.  
  347.  
  348. EXPORT_SYMBOL(set_current_groups);
  349.  
  350.  
  351.  
  352. SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist)
  353.  
  354. {
  355.  
  356. const struct cred *cred = current_cred();
  357.  
  358. int i;
  359.  
  360.  
  361.  
  362. if (gidsetsize < 0)
  363.  
  364. return -EINVAL;
  365.  
  366.  
  367.  
  368. /* no need to grab task_lock here; it cannot change */
  369.  
  370. i = cred->group_info->ngroups;
  371.  
  372. if (gidsetsize) {
  373.  
  374. if (i > gidsetsize) {
  375.  
  376. i = -EINVAL;
  377.  
  378. goto out;
  379.  
  380. }
  381.  
  382. if (groups_to_user(grouplist, cred->group_info)) {
  383.  
  384. i = -EFAULT;
  385.  
  386. goto out;
  387.  
  388. }
  389.  
  390. }
  391.  
  392. out:
  393.  
  394. return i;
  395.  
  396. }
  397.  
  398.  
  399.  
  400. /*
  401.  
  402.  * SMP: Our groups are copy-on-write. We can set them safely
  403.  
  404.  * without another task interfering.
  405.  
  406.  */
  407.  
  408.  
  409.  
  410. SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
  411.  
  412. {
  413.  
  414. struct group_info *group_info;
  415.  
  416. int retval;
  417.  
  418.  
  419.  
  420. if (!nsown_capable(CAP_SETGID))
  421.  
  422. return -EPERM;
  423.  
  424. if ((unsigned)gidsetsize > NGROUPS_MAX)
  425.  
  426. return -EINVAL;
  427.  
  428.  
  429.  
  430. group_info = groups_alloc(gidsetsize);
  431.  
  432. if (!group_info)
  433.  
  434. return -ENOMEM;
  435.  
  436. retval = groups_from_user(group_info, grouplist);
  437.  
  438. if (retval) {
  439.  
  440. put_group_info(group_info);
  441.  
  442. return retval;
  443.  
  444. }
  445.  
  446.  
  447.  
  448. retval = set_current_groups(group_info);
  449.  
  450. put_group_info(group_info);
  451.  
  452.  
  453.  
  454. return retval;
  455.  
  456. }
  457.  
  458.  
  459.  
  460. /*
  461.  
  462.  * Check whether we're fsgid/egid or in the supplemental group..
  463.  
  464.  */
  465.  
  466. int in_group_p(gid_t grp)
  467.  
  468. {
  469.  
  470. const struct cred *cred = current_cred();
  471.  
  472. int retval = 1;
  473.  
  474.  
  475.  
  476. if (grp != cred->fsgid)
  477.  
  478. retval = groups_search(cred->group_info, grp);
  479.  
  480. return retval;
  481.  
  482. }
  483.  
  484.  
  485.  
  486. EXPORT_SYMBOL(in_group_p);
  487.  
  488.  
  489.  
  490. int in_egroup_p(gid_t grp)
  491.  
  492. {
  493.  
  494. const struct cred *cred = current_cred();
  495.  
  496. int retval = 1;
  497.  
  498.  
  499.  
  500. if (grp != cred->egid)
  501.  
  502. retval = groups_search(cred->group_info, grp);
  503.  
  504. return retval;
  505.  
  506.  
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.c:1:8: error: variable 'init_groups' has initializer but incomplete type
 struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; 
        ^
prog.c:1:8: error: unknown field 'usage' specified in initializer
prog.c:1:8: warning: implicit declaration of function 'ATOMIC_INIT' [-Wimplicit-function-declaration]
prog.c:1:8: warning: excess elements in struct initializer
prog.c:1:8: warning: (near initialization for 'init_groups')
prog.c: In function 'groups_alloc':
prog.c:9:29: error: 'NGROUPS_PER_BLOCK' undeclared (first use in this function)
     nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; 
                             ^
prog.c:9:29: note: each undeclared identifier is reported only once for each function it appears in
prog.c:12:5: warning: implicit declaration of function 'kmalloc' [-Wimplicit-function-declaration]
     group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); 
     ^
prog.c:12:33: error: dereferencing pointer to incomplete type
     group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); 
                                 ^
prog.c:12:63: error: 'gid_t' undeclared (first use in this function)
     group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); 
                                                               ^
prog.c:12:70: error: expected expression before ')' token
     group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); 
                                                                      ^
prog.c:12:73: error: 'GFP_USER' undeclared (first use in this function)
     group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); 
                                                                         ^
prog.c:14:16: error: 'NULL' undeclared (first use in this function)
         return NULL; 
                ^
prog.c:16:15: error: dereferencing pointer to incomplete type
     group_info->ngroups = gidsetsize; 
               ^
prog.c:17:15: error: dereferencing pointer to incomplete type
     group_info->nblocks = nblocks; 
               ^
prog.c:18:5: warning: implicit declaration of function 'atomic_set' [-Wimplicit-function-declaration]
     atomic_set(&group_info->usage, 1); 
     ^
prog.c:18:27: error: dereferencing pointer to incomplete type
     atomic_set(&group_info->usage, 1); 
                           ^
prog.c:20:23: error: 'NGROUPS_SMALL' undeclared (first use in this function)
     if (gidsetsize <= NGROUPS_SMALL) 
                       ^
prog.c:21:19: error: dereferencing pointer to incomplete type
         group_info->blocks[0] = group_info->small_block; 
                   ^
prog.c:21:43: error: dereferencing pointer to incomplete type
         group_info->blocks[0] = group_info->small_block; 
                                           ^
prog.c:24:20: error: 'b' undeclared (first use in this function)
             gid_t *b; 
                    ^
prog.c:25:13: warning: implicit declaration of function '__get_free_page' [-Wimplicit-function-declaration]
             b = (void *)__get_free_page(GFP_USER); 
             ^
prog.c:28:23: error: dereferencing pointer to incomplete type
             group_info->blocks[i] = b; 
                       ^
prog.c:38:9: warning: implicit declaration of function 'free_page' [-Wimplicit-function-declaration]
         free_page((unsigned long)group_info->blocks[i]); 
         ^
prog.c:38:44: error: dereferencing pointer to incomplete type
         free_page((unsigned long)group_info->blocks[i]); 
                                            ^
prog.c:42:5: warning: implicit declaration of function 'kfree' [-Wimplicit-function-declaration]
     kfree(group_info); 
     ^
prog.c: At top level:
prog.c:50:1: warning: data definition has no type or storage class
 EXPORT_SYMBOL(groups_alloc); 
 ^
prog.c:50:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:50:1: warning: parameter names (without types) in function declaration
prog.c: In function 'groups_free':
prog.c:58:19: error: dereferencing pointer to incomplete type
     if (group_info->blocks[0] != group_info->small_block) { 
                   ^
prog.c:58:44: error: dereferencing pointer to incomplete type
     if (group_info->blocks[0] != group_info->small_block) { 
                                            ^
prog.c:62:35: error: dereferencing pointer to incomplete type
         for (i = 0; i < group_info->nblocks; i++) 
                                   ^
prog.c:64:48: error: dereferencing pointer to incomplete type
             free_page((unsigned long)group_info->blocks[i]); 
                                                ^
prog.c: At top level:
prog.c:74:1: warning: data definition has no type or storage class
 EXPORT_SYMBOL(groups_free); 
 ^
prog.c:74:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:74:1: warning: parameter names (without types) in function declaration
prog.c:80:27: error: unknown type name 'gid_t'
 static int groups_to_user(gid_t __user *grouplist, 
                           ^
prog.c:122:5: error: unknown type name 'gid_t'
     gid_t __user *grouplist) 
     ^
prog.c: In function 'groups_sort':
prog.c:166:32: error: dereferencing pointer to incomplete type
     int gidsetsize = group_info->ngroups; 
                                ^
prog.c:188:13: error: unknown type name 'gid_t'
             gid_t tmp = GROUP_AT(group_info, right); 
             ^
prog.c:188:13: warning: implicit declaration of function 'GROUP_AT' [-Wimplicit-function-declaration]
prog.c:194:45: error: lvalue required as left operand of assignment
                 GROUP_AT(group_info, right) = 
                                             ^
prog.c:204:41: error: lvalue required as left operand of assignment
             GROUP_AT(group_info, right) = tmp; 
                                         ^
prog.c: At top level:
prog.c:218:56: error: unknown type name 'gid_t'
 int groups_search(const struct group_info *group_info, gid_t grp) 
                                                        ^
prog.c:276:41: warning: 'struct cred' declared inside parameter list
 int set_groups(struct cred *new, struct group_info *group_info) 
                                         ^
prog.c:276:41: warning: its scope is only this definition or declaration, which is probably not what you want
prog.c: In function 'set_groups':
prog.c:280:5: warning: implicit declaration of function 'put_group_info' [-Wimplicit-function-declaration]
     put_group_info(new->group_info); 
     ^
prog.c:280:23: error: dereferencing pointer to incomplete type
     put_group_info(new->group_info); 
                       ^
prog.c:284:5: warning: implicit declaration of function 'get_group_info' [-Wimplicit-function-declaration]
     get_group_info(group_info); 
     ^
prog.c:286:8: error: dereferencing pointer to incomplete type
     new->group_info = group_info; 
        ^
prog.c: At top level:
prog.c:294:1: warning: data definition has no type or storage class
 EXPORT_SYMBOL(set_groups); 
 ^
prog.c:294:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:294:1: warning: parameter names (without types) in function declaration
prog.c: In function 'set_current_groups':
prog.c:322:5: warning: implicit declaration of function 'prepare_creds' [-Wimplicit-function-declaration]
     new = prepare_creds(); 
     ^
prog.c:322:9: warning: assignment makes pointer from integer without a cast
     new = prepare_creds(); 
         ^
prog.c:326:17: error: 'ENOMEM' undeclared (first use in this function)
         return -ENOMEM; 
                 ^
prog.c:330:22: warning: passing argument 1 of 'set_groups' from incompatible pointer type
     ret = set_groups(new, group_info); 
                      ^
prog.c:276:5: note: expected 'struct cred *' but argument is of type 'struct cred *'
 int set_groups(struct cred *new, struct group_info *group_info) 
     ^
prog.c:334:9: warning: implicit declaration of function 'abort_creds' [-Wimplicit-function-declaration]
         abort_creds(new); 
         ^
prog.c:342:5: warning: implicit declaration of function 'commit_creds' [-Wimplicit-function-declaration]
     return commit_creds(new); 
     ^
prog.c: At top level:
prog.c:348:1: warning: data definition has no type or storage class
 EXPORT_SYMBOL(set_current_groups); 
 ^
prog.c:348:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:348:1: warning: parameter names (without types) in function declaration
prog.c:352:28: error: expected ')' before 'int'
 SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist) 
                            ^
prog.c:410:28: error: expected ')' before 'int'
 SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) 
                            ^
prog.c:466:16: error: unknown type name 'gid_t'
 int in_group_p(gid_t grp) 
                ^
prog.c:486:1: warning: data definition has no type or storage class
 EXPORT_SYMBOL(in_group_p); 
 ^
prog.c:486:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' [-Wimplicit-int]
prog.c:486:1: warning: parameter names (without types) in function declaration
prog.c:490:17: error: unknown type name 'gid_t'
 int in_egroup_p(gid_t grp) 
                 ^
stdout
Standard output is empty